C # Лучший способ отозвать клиентское приложение с промежуточными результатами из пула потоков - PullRequest
0 голосов
/ 14 июня 2009

Я написал библиотеку C #, в которой есть метод для подсчета слов из нескольких проходов текста параллельно. Отрывки текста задаются в виде символьных потоков, где при каждом вызове getnextchar() происходит случайная задержка. Мой библиотечный метод должен взять массив этих символьных потоков и вернуть комбинированный подсчет частоты слов. Для этого у меня есть безопасная общая структура данных с частотой слов и поток для чтения каждого потока символов и обновления общей коллекции. Когда все потоки завершены, я возвращаю структуру данных клиентскому приложению.

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

Моя проблема заключается в том, что при обратном вызове клиента с промежуточными результатами мне приходится блокировать свою общую структуру данных и ждать, пока клиентское приложение вернется из обратного вызова, прежде чем я смогу разблокировать ее. Пока выполняется обратный вызов, все рабочие потоки блокируются в ожидании блокировки структуры данных. Это не похоже на разумную вещь, потому что я не думаю, что должен полагаться или доверять клиентскому коду, чтобы он возвращался быстро или даже вообще. Тем не менее, они могут думать только о том, что делать это, не полагаясь на код клиента, - это сделать копию или снимок моей структуры данных и передать ее клиенту через обратный вызов. Это происходит за счет памяти и вычислений, но после создания копии рабочие могут продолжить обновление общей коллекции, а обратный вызов может делать все, что захочет.

У меня вопрос в два раза:

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

2) Есть ли способ решить эту проблему, который не делает ни один из вышеперечисленных?

Ответы [ 2 ]

2 голосов
/ 14 июня 2009

Я бы определенно сказал, что большее из двух зол доверяет клиенту. Обратный вызов неизвестного кода при удержании блокировки - это рецепт для взаимоблокировок и худших сценариев. Да, вы будете платить за накладные расходы, чтобы сделать снимок вашей структуры и вернуть его. Но дополнительная память для снимка перевешивает риск вызова при удержании блокировки.

Я сталкивался с подобными ситуациями, и до сих пор снимок не был проблемой. Если это так, вы можете найти несколько способов обойти это. В том числе увеличение частоты, с которой вы звоните клиенту, что уменьшит объем данных, которые вы должны снимать в данный момент времени.

Другим способом решения этой проблемы является использование неизменяемой структуры данных. Когда вы будете готовы поговорить с клиентом, просто прервите текущую версию и передайте ее клиенту. Позвольте вашим фоновым потокам начать создавать новый.

0 голосов
/ 14 июня 2009

Я недавно столкнулся с такой проблемой при написании библиотеки - она ​​не была точно такой же, но основной вопрос был таким же - насколько вы можете доверять своему клиенту, который использует вашу библиотеку. Что вы делаете, когда вы можете добиться лучшей производительности, если вы можете положиться на клиента, чтобы сделать определенную вещь?

В результате мы получили два пути кода и флаг, который клиент мог установить на нашем объекте, чтобы указать, какой путь выбрать. По сути, это был флаг «Вы можете мне доверять». Если бы он не был установлен (по умолчанию), библиотека предположила бы, что имеет дело с клиентом, которому она не могла доверять, и никогда не давала бы клиенту прямую ссылку на внутренние структуры данных - она ​​всегда получала копию. Однако, если клиент установит этот флаг, он получит прямой доступ к реальной структуре и должен будет следовать правилам, которые мы установили (задокументировано как для флага, так и для метода доступа).

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

...