Необходимо ли вызывать EndInvoke в обратном вызове из EventHandler.BeginInvoke (C # .Net 3.5) - PullRequest
3 голосов
/ 15 ноября 2010

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

На клиенте обратный вызов с сервера (в данном случае «OnMessage») запускает событие на стороне клиента, которое должно передаваться в фоновом режиме. У меня есть CallbackBehavior ConcurrencyMode клиента, установленный в Single (по крайней мере, на данный момент). Поэтому, чтобы сделать ответ на обратный вызов, а не вызывать обработчик как обычно (либо обработчик (отправитель, eventargs или handler.Invoke ...), я вызываю handler.BeginInvoke.

Все работает нормально, но при обратном вызове я задаюсь вопросом, нужно ли мне явно вызывать EndInvoke или я в принципе ничего не могу сделать (вот мое отсутствие опыта многопоточности).

public void OnMessage(Message message)
{
    EventHandler<MessageEventArgs> handler = OnServerMessage;
    if (handler != null)
        handler.BeginInvoke(this, new MessageEventArgs(message), CompleteHandler, handler);
}

public void CompleteHandler(IAsyncResult result)
{
    ((EventHandler<MessageEventArgs>)result.AsyncState).EndInvoke(result);
}

Могу ли я заменить CompleteHandler прямой ссылкой на обработчик. EndInvoke, или пустой метод, или, может быть, я должен что-то еще сделать?

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

Ответы [ 3 ]

9 голосов
/ 15 ноября 2010

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

2 голосов
/ 15 ноября 2010

Вам необходимо заключить код CompleteHandler в блок try / catch, а затем правильно обработать любое исключение, выданное EndInvoke.Прямо сейчас сервис работает в «лабораторных» условиях, но когда что-то идет не так, вы даже не узнаете, , что идет не так, потому что вы неправильно обрабатываете / регистрируете ошибки.

Что касается вопроса получения состояния из глобального состояния, или из IAsyncResult, или из закрытия обратного вызова: IASyncResult.AsyncState является наиболее универсальным решением и будет продолжать работать правильно после того, как кто-то еще выполнит рефакторинг вызывающегокод до неузнаваемости.

1 голос
/ 15 ноября 2010

Как правило, BeginInvoke запускает асинхронную операцию, тогда как EndInvoke ожидает ее завершения. Так что это зависит от ваших намерений: если вы хотите гарантировать, что ваш асинхронный код завершен, вам нужно EndInvoke, иначе нет.

(однако учтите, что если ваш BeginInvoke вызывает в тот же поток , где вы на самом деле находитесь (это допустимое использование, только код будет запущен в следующем цикле Dispatcher), вы должны не используйте EndInvoke, так как это может привести к тупику. Но, похоже, это не ваш случай.)

...