Начать конец вызова асинхронного метода

1

Вот фрагмент кода от Microsoft. У меня есть сомнение в асинхронном вызове метода.

поскольку мы вызываем end.Invoke после Begin-invoke, похоже, что мы делаем синхронный вызов. потому что мы ждем возвращенного значения асинхронного вызова.

что произойдет, если асинхронный метод не завершится, пока мы вызываем end.invoke. можем ли мы просто перейти к следующему утверждению или нам нужно подождать.

если это происходит в многопоточной среде, как они обрабатывают сигнал обратного вызова для исправления потока.

public void DemoEndInvoke()
{
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    // Initiate the asynchronous call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);  

    // Do some useful work here. This would be work you want to have
    // run at the same time as the asynchronous call.

    // Retrieve the results of the asynchronous call.
    s = dlgt.EndInvoke (out iExecThread, ar) ;  

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                               and the number {1}", s, iExecThread.ToString() ) );
}
Теги:
multithreading
asynchronous
.net-3.5
begininvoke

2 ответа

4

что произойдет, если асинхронный метод не завершится, пока мы вызываем end.invoke. можем ли мы просто перейти к следующему утверждению или нам нужно подождать.

Да, EndInvoke - это блокирующий вызов. Вы можете сделать все это намного проще, если вы используете метод TaskFactory.FromAsync. Это преобразует ваш API, чтобы вернуть задачу, которую вы можете await.

Ваш код должен выглядеть примерно так (я его не компилировал):

public async void DemoEndInvoke()
{
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    await Task.Factory.FromAsync(MethodDelegate.BeginInvoke, MethodDelegate.EndInvoke, iExecThread);

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", and the number {1}", s, iExecThread.ToString() ) );
}

Используя await компилятор будет генерировать конечный автомат, который сохраняет текущий SynchronizationContext а затем восстанавливает его после завершения задачи и выполняет оставшуюся часть метода в том же SynchronizationContext. Если вы await в потоке пользовательского интерфейса, код после await также будет выполняться в потоке пользовательского интерфейса. Однако для консольных приложений и модульных тестов это не так.

Если все, что вы пытаетесь сделать, это запустить длинный метод в фоновом потоке, вы можете просто использовать Task.Run в.net 4.5 или TaskFactory.StartNew в.net 4.0. Разницу между ними см. В этой статье.

public async void DemoEndInvoke()
{
    await Task.Run(() => this.LongRunningMethod());

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", and the number {1}", s, iExecThread.ToString() ) );
}
  • 0
    Я использую .Net 3.5. Так что все вещи за асинхронными. вызов состоит в том, что он начнется в новом потоке, и мы можем сделать некоторую работу перед вызовом метода endinvoke. Мое требование - вызывать и оставлять, мне все равно, после этого все остальное будет обрабатываться методом assync. мне не нужно ничего делать с обратным вызовом
  • 0
    В первом примере вы MethodDelegate.BeginInvoke выполнить в фоновом потоке, что, в свою очередь, сообщает this.LongRunningMethod о запуске в фоновом потоке; там много дополнительной работы.
0

Вам придется подождать; от синхронных асинхронных вызовов:

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

Механизм, который используется для выполнения блокировки, скорее всего будет выглядеть следующим образом:

IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);

// wait for async invocation to complete
ar.AsyncWaitHandle.WaitOne()

Но вы должны позвонить EndInvoke (см. Этот вопрос для более подробного обсуждения).

Если вы не хотите ждать, вам необходимо использовать асинхронный обратный вызов для выполнения EndInvoke:

dlgt.BeginInvoke(3000, out iExecThread, ar => dlgt.EndInvoke(out iExecThread, ar), null);

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


С учетом сказанного,.NET получил отличные асинхронные API программирования, начиная с.NET 4; более новые модели лучше структурированы, более мощные и удобны в работе (особенно в 4.5). Если у вас есть этот параметр, вы должны посмотреть .NET TPL и .NET 4.5 TAP.

  • 0
    Так что все вещи за асинхронными. вызов состоит в том, что он начнется в новом потоке, и мы можем сделать некоторую работу перед вызовом метода endinvoke. Мое требование - вызывать и оставлять, мне все равно, после этого все остальное будет обрабатываться методом assync.
  • 0
    Я добавил пример, чтобы не ждать.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню