|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
решил заморочиться с кэшированием. Задача совершенно обыденная - есть сервис, дает данные, нужно кэшировать.Сервис конечно многопоточный. Вот сейчас реализовано примерно так: Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24.
все бы хорошо, но проблема в том ,что когда сервису с ключом 2 нужны данные,он по сути будет ждать пока тянутся данные с ключом 1 и тд. А тянуться они, например долго. Непосредственно безопасность самого добавления key-value решается за нас memoryCahce. Короче Уг подумал я и решил погуглить. Накнуля на шаблон RWLockSlim, например string.Intern Получилось так: Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43.
Замерял результат на 10 разных ключах, 10 потоков. ВОт пример замеров: Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
Результат огорчает в обоих случаях = +-10 сек (т.е. по секунде на запрос). И тут пришла в голову мысль лочить "ключи". Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26.
Результат +- 1 секунда. Т.е. почти в 10 раз лучше! Вообщем обсудите, зачмырите, а лучше дайте свой готовый враппер на этот случай! Пошел спать. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.10.2014, 22:59 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivan , Ну нормально, в принципе. Вы таким образом итеративно пришли к подходу, который называется "striped lock" (от слова stripe - полоса). Если время на прогрев кэша не критично, то я бы вообще убрал ConcurrentDictionary. Например, наткнутся два потока на отсутствие одного и того же ключа - да и хер с ним. Пускай каждый из них сделает по отдельному запросу. Если у вас никто от этого не умрет - то рекомендую сделать именно так. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.10.2014, 23:29 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
1) Если у вас кэш планируется использовать в многопоточной среде, то и накладываться локи должны в нем, а не перекидывать эту ответственность на внешние классы. 2) Почему не какой-нибудь популярный inmemory db? 3) netivanкогда сервису с ключом 2 нужны данные,он по сути будет ждать пока тянутся данные с ключом 1 и тд. А тянуться они, например долго. Почему? В вышеприведенном коде возвращается ссылка на string, а не копия строки 4) netivan Код: c# 1. 2. 3. 4. 5. 6. 7.
Зачем вы LoadData делаете в секции lock? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 10:07 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivan, Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28.
... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 10:46 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28.
поправил ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 10:48 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
hVostt Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28.
поправил да, про дабл чек я потом вспомнил. Но если пришел запрос с 2 одинаковыми значениями, Load будет выполняться 2 раза. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 11:23 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Arm791) Если у вас кэш планируется использовать в многопоточной среде, то и накладываться локи должны в нем, а не перекидывать эту ответственность на внешние классы. 2) Почему не какой-нибудь популярный inmemory db? 3) netivanкогда сервису с ключом 2 нужны данные,он по сути будет ждать пока тянутся данные с ключом 1 и тд. А тянуться они, например долго. Почему? В вышеприведенном коде возвращается ссылка на string, а не копия строки 4) netivan Код: c# 1. 2. 3. 4. 5. 6. 7.
Зачем вы LoadData делаете в секции lock? да, с Load косяк) Уже потом понял. Но тем не менее лочить по ключу помойму хорошая идея. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 11:25 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Пока собирался писать - про дабл чек вы уже вспомнили. MemoryCache (MSDN): This type is thread safe. Из коробки должен давать потокобезопасные Add/Get/Remove. Само же содержимое уже нужно блокировать. lock - самый тяжелый способ. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 11:28 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
tAZARПока собирался писать - про дабл чек вы уже вспомнили. MemoryCache (MSDN): This type is thread safe. Из коробки должен давать потокобезопасные Add/Get/Remove. Само же содержимое уже нужно блокировать. lock - самый тяжелый способ. вот с ним и думаю как лучше написать "враппер". Ибо стандратная процедура: Get(key) - нет данных - Получаем- Записываем. Возможно тут lock лишний вообще не нужен. http://msdn.microsoft.com/ru-ru/library/system.threading.readerwriterlockslim(v=vs.110).aspx вот тут пример с Dictionary<>. Возможно тоже самое реализовано в MemoryCache уже. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 11:31 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivanда, с Load косяк) Уже потом понял. Но тем не менее лочить по ключу помойму хорошая идея. Лочить что-либо вообще не очень хорошая идея, чем больше локов, тем медленнее все работает. Это неизбежное зло, но его нужно минимизировать. Как по общему количеству, так и по действиям, которые в этом локе происходят. Для примера - зачем придумали Concurrent* коллекции, если есть обычные + lock? Далее, если опустить необходимость блокировки коллекции ключей, я совершенно не вижу причины делать это вне класса MemoryCache. Как и механизм получения данных по ключу. netivanда, про дабл чек я потом вспомнил. Но если пришел запрос с 2 одинаковыми значениями, Load будет выполняться 2 раза. Нувыжэксперт, придумайте что-нибудь :-) Например, ведите еще одну коллекцию - пришедших запросов :-) ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 11:33 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Arm79netivanда, с Load косяк) Уже потом понял. Но тем не менее лочить по ключу помойму хорошая идея. Лочить что-либо вообще не очень хорошая идея, чем больше локов, тем медленнее все работает. Это неизбежное зло, но его нужно минимизировать. Как по общему количеству, так и по действиям, которые в этом локе происходят. Для примера - зачем придумали Concurrent* коллекции, если есть обычные + lock? Далее, если опустить необходимость блокировки коллекции ключей, я совершенно не вижу причины делать это вне класса MemoryCache. Как и механизм получения данных по ключу. netivanда, про дабл чек я потом вспомнил. Но если пришел запрос с 2 одинаковыми значениями, Load будет выполняться 2 раза. Нувыжэксперт, придумайте что-нибудь :-) Например, ведите еще одну коллекцию - пришедших запросов :-) дык я и думаю. Про lock я согласен - чем меньше тем лучше :). Никто не в курсе что внутри MemoryCache? Или рефлектор открывать) авторНапример, ведите еще одну коллекцию - пришедших запросов :-) ну типа это я и сделал: Код: c# 1. 2. 3. 4. 5. 6. 7.
+ только дабл чек добавить ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 11:40 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivanда, про дабл чек я потом вспомнил. Но если пришел запрос с 2 одинаковыми значениями, Load будет выполняться 2 раза. в этом нет ничего страшного, даже наоборот так лучше. так как при локе, второй поток не получит данные пока они не будут записаны в кеш, а так реализуется быстрый кеш на уровне данных (например, базы данных), и второй поток получает данные на столько быстро, на сколько это возможно. все ваши заморочки с дополнительным ключом на строке, это лишний ненужный геморрой. суть в том, чтобы взять данные из кеша, если он там есть или из источника данных. и никого при этом не ждать. иначе огребёте по полной. дабл чек нужен, чтобы не ложить в кеш данные два раза, больше ни на что это не влияет. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 11:55 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
hVosttnetivanда, про дабл чек я потом вспомнил. Но если пришел запрос с 2 одинаковыми значениями, Load будет выполняться 2 раза. в этом нет ничего страшного, даже наоборот так лучше. так как при локе, второй поток не получит данные пока они не будут записаны в кеш, а так реализуется быстрый кеш на уровне данных (например, базы данных), и второй поток получает данные на столько быстро, на сколько это возможно. все ваши заморочки с дополнительным ключом на строке, это лишний ненужный геморрой. суть в том, чтобы взять данные из кеша, если он там есть или из источника данных. и никого при этом не ждать. иначе огребёте по полной. дабл чек нужен, чтобы не ложить в кеш данные два раза, больше ни на что это не влияет. ну зато грузим сервер 2 раза :) А может там запрос 30 минут выполняется?! ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:00 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivan, уж не знаю что Вы кешируете, уж не говорите что запросы к базе и результаты ответов, а то я войду в ступор.. ЧТо кешируем? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:03 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Где-то в степиnetivan, уж не знаю что Вы кешируете, уж не говорите что запросы к базе и результаты ответов, а то я войду в ступор.. ЧТо кешируем? ну примерно. Только это запрос не к БД, а к другой системе. Например, история операций. Раз в Х минут она обновляется из кеша. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:05 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivantAZARПока собирался писать - про дабл чек вы уже вспомнили. MemoryCache (MSDN): This type is thread safe. Из коробки должен давать потокобезопасные Add/Get/Remove. Само же содержимое уже нужно блокировать. lock - самый тяжелый способ. вот с ним и думаю как лучше написать "враппер". Ибо стандратная процедура: Get(key) - нет данных - Получаем- Записываем. Возможно тут lock лишний вообще не нужен. http://msdn.microsoft.com/ru-ru/library/system.threading.readerwriterlockslim(v=vs.110).aspx вот тут пример с Dictionary<>. Возможно тоже самое реализовано в MemoryCache уже. Именно этот лок лишний. С содержимым достаточно быстро будет работать RW lock или по ситуации уже, смотря что кешируете. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:07 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
tAZARnetivanпропущено... вот с ним и думаю как лучше написать "враппер". Ибо стандратная процедура: Get(key) - нет данных - Получаем- Записываем. Возможно тут lock лишний вообще не нужен. http://msdn.microsoft.com/ru-ru/library/system.threading.readerwriterlockslim(v=vs.110).aspx вот тут пример с Dictionary<>. Возможно тоже самое реализовано в MemoryCache уже. Именно этот лок лишний. С содержимым достаточно быстро будет работать RW lock или по ситуации уже, смотря что кешируете. не понял, какой лишний? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:11 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivan, ну а че ключ строка? на словах что ли передаете? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:12 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivanну зато грузим сервер 2 раза :) А может там запрос 30 минут выполняется?! какая разница? нагрузку с сервера вы существенно таким образом не снимите, зато поимеете проблем. зачем это вам надо? кроме того, говорить о нагрузках без тестирования не имеет смысла. ещё раз. суть кеширования, это отдать данные из кеша если они там есть . всё. не стоит превращать кеш в промежуточный источник данных. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:13 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Где-то в степиnetivan, ну а че ключ строка? на словах что ли передаете? ну там GetHasCode(), но разве это принципиально? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:13 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivan, принципиально как вы подходите к этому. если с парадигмы распределенных вычислений близко к ста процентам все в конце концов замыкается на базе тут кеширование выгодней уложить на плечи орм и в общем то все они прекрасно это поддерживают из коробки, ну кинут в меня камень что недоОрм EF это не умеет, но есть примеры где прикручивают второй уровень и к этому чуду,( о последней версии умолчу), если с точки зрения , как говорит МСУ, трех звенки в ипостасии, то топик имеет актуальность все зависит как смотреть.. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:25 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivan, У вас он сейчас 1, на Add, который заявлен потокобезопасным. Сам этот кеш использовал с блокировками содержимого через rw lock, conditional variable (ну, была там одна ситуация..) и неблокирующими операциями с содержимым. Стандартные операции не лочили никогда. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:30 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Где-то в степину кинут в меня камень что недоОрм EF это не умеет лови камень https://efcache.codeplex.com/ http://msdn.microsoft.com/ru-ru/magazine/hh394143.aspx всё там есть. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:33 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
netivan ну вот видишь, и оно тоже умеет )) ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:36 |
|
пишу логику с кэшем - критикуйте
|
|||
---|---|---|---|
#18+
Где-то в степиnetivan ну вот видишь, и оно тоже умеет )) у меня нет никакого EF, даже БД нет=). + есть ручное Policy обновления, к сожалению. Что имеем то имеем. Вот смотрю на пример с RWLock и если честно не очень понимаю зачем там так накрутили. http://msdn.microsoft.com/ru-ru/library/system.threading.readerwriterlockslim(v=vs.110).aspx если есть Concurrent. Видимо только для примера. Вроде бы понял,что локов в MemoryCache достаточно. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.10.2014, 12:52 |
|
|
start [/forum/topic.php?fid=20&fpage=106&tid=1402369]: |
0ms |
get settings: |
7ms |
get forum list: |
11ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
38ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
77ms |
get tp. blocked users: |
1ms |
others: | 37ms |
total: | 192ms |
0 / 0 |