2015-01-14 5 views
1

Я вызываю службу мыла, которая дает идентификатор, возвращает объект. Каждый запрос принимает только один идентификатор, поэтому мне нужно многократно вызывать веб-службу для загрузки всех объектов (10k).Как уменьшить количество генерируемых событий

У меня есть несколько потоков, обрабатывающих запросы, и все они вставляют сущности в параллельный словарь. Весь процесс занимает несколько минут, но я хотел бы время от времени передавать результаты вызывающему, скажем, каждые 100 полученных объектов.

Я знаю, что могу использовать события покупки Я не хочу запускать событие для каждого получаемого объекта. Кроме того, я не хочу проверять каждую полученную сущность, если счетчик достигает 100, я боюсь, что производительность, так как счетчик должен быть синхронизирован.

Что вы предложите? Должен ли я использовать события? Что-нибудь еще?

+1

Вы не можете изменить службу SOAP, чтобы принять диапазон идентификаторов? – DavidG

+0

Нет, это не контролируется мной, и практически невозможно изменить это в эффективном для времени способом. – wollow

+0

Я бы очень опасался использования многопоточности в этом контексте. Цитата из старой шутки ... У программиста была проблема. Он подумал про себя: «Я знаю, я разберусь с нитками!». имеет теперь проблемы. два он – DavidG

ответ

2

Если у вас есть возможность «загружать» ваши потоки, это может сработать.

Используйте Task вместо Thread, а затем создайте их. И, наконец, использовать Task.WaitAll:

// Construct started tasks 
Task[] tasks = new Task[100]; 
for (int i = 0; i < 100; i++) 
{ 
    //action is your method as a delegate 
    tasks[i] = Task.Factory.StartNew(action); 
} 

Task.WaitAll(tasks); 
FireHundredComplete(); //Invoke your event 

Теперь вам нужно будет запустить каждый из тех на отдельном потоке/задачи, так как Task.WaitAll будет блокировать (и его не ASync, так что вы не можете await это).

У вас также будет много этих событий, стреляющих в кажущиеся случайные интервалы, так как каждый набор задач может быть завершен в любое время. Синхронизация может все еще быть проблемой.

+0

Я на самом деле уже использую задачи. Однако в моем случае это приведет к еще большей задержке. Я протестировал аналогичный подход, и на самом деле гораздо быстрее запросить как можно больше объектов (служба может вернуть значение null, и в этом случае запрос должен быть сделан снова, возможно, даже больше одного раза). Не могу дождаться завершения первого 100, мне нужно запросить как можно больше. – wollow

+0

@ user1448276 Правильно, поэтому я предложил создать целую кучу этих «партий» в * parallel *. У вас все еще есть проблемы с синхронизацией (как я уже отмечал), но это связано с проблемой счетчика. – BradleyDotNET

+0

Я вижу. Кроме того, когда событие запущено, связанный с ним метод будет выполнен в неправильном потоке. Являются ли события потоками безопасными? Я имею в виду, что за короткий промежуток времени я запускаю 200 событий из разных потоков, есть ли шанс, что я их потеряю? – wollow

2

Кроме того, я не хочу проверять каждую полученную сущность, если счетчик достигает 100, я боюсь, что производительность будет работать, поскольку счетчик должен быть синхронизирован.

Не быть; приращение счетчика в синхронизированном блоке - insanely quick; замки на самом деле очень дешево, так что простая реализация может быть просто:

bool raiseEvent; 
lock(sharedLock) { 
    raiseEvent = (++counter % EventFrequency) == 0; 
} 
if(raiseEvent) {...} 

Однако, вы можете сделать это еще более эффективно с блокировкой:

if((Interlocked.Increment(ref counter) % EventFrequency) == 0) 
{ ... } 

Однако! Это, по-видимому, означает, что реальная проблема «производительности» здесь вызывает огромное количество вызовов веб-сервисов. Я настоятельно рекомендую сделать это более пакетным. Это не обязательно означает «все в одной партии», но 100 партий из 100 предметов будут работать намного лучше, чем 10 000 индивидуальных вызовов (и часто также будут работать лучше, чем 1 партия из 10 000 предметов).

Смежные вопросы