2016-04-28 5 views
2

У меня есть простой код, где я пытаюсь лучше понять, как метод можно вызывать асинхронно на C#.Асинхронный вызов синхронного метода

У меня есть функция под названием Function1, которую я хочу запустить асинхронно

static void Function1(out int threadId) 
{ 
    Console.WriteLine("I'm inside Function 1. Going to sleep for 7 seconds..."); 
    Thread.Sleep(7000); 
    Console.WriteLine("I'm awake now"); 
    threadId = Thread.CurrentThread.ManagedThreadId; 
} 

Тогда у меня есть вторая функция Function2, которую я хочу работать в нормальном режиме (синхронно)

static void Function2() 
{ 
    Thread.Sleep(3000); 
    Console.WriteLine("I'm inside Function 2"); 
} 

Я также создан делегат с той же подписью метода, что и Function1

delegate void AsyncMethodCaller(out int threadId); 

А вот мой основной метод вызова:

static void Main(string[] args) 
{ 
    int threadId; 
    AsyncMethodCaller caller = new AsyncMethodCaller(Function1); 
    caller.BeginInvoke(out threadId, null, null); 
    Function2(); 
} 

В моей основной метод, я ожидаю Function1 для запуска асинхронно; а затем без ожидания на нем, чтобы закончить, Function2 выполняет. Поэтому я ожидаю, что следующий вывод:

Я внутри асинхронной функции 1. Иду спать в течение 7 секунд ...
я внутри функции 2
Я проснулся

Вместо этого я просто получить следующий вывод:

Я внутри асинхронной функции 1. спать в течение 7 секунд ...
я внутри функции 2

Почему мое ожидание отличается от реальности? почему линия «Я просыпаюсь сейчас» никогда не достигала?

Спасибо

+0

Поскольку вы не дождались завершения функции 1 до выхода из Главного – MickyD

+0

, согласитесь с @MickyD. –

+0

Мне нужно создать делегат каждый раз, когда я хочу вызвать метод асинхронно? – IsaacBok

ответ

4

Основные правила прижизненные процесс для .NET является то, что процесс завершается, когда все переднего плана нити вышли. Любые фоновые потоки просто прерываются; процесс не будет ждать их.

Кроме того, когда вы вызываете метод делегата BeginInvoke(), это неявно вызывает вызов делегата с использованием пула потоков. Пул потоков выполнен полностью из фоновых потоков.

Другими словами, когда вы звоните BeginInvoke(), вы сообщаете .NET, чтобы вызвать делегата, используя поток, который сам по себе не гарантирует его собственное время жизни. Этот поток может (и в этом случае) прерываться после того, как выйдет один основной поток переднего плана процесса, который возникает сразу после вызова Function2().

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

IAsyncResult result = caller.BeginInvoke(out threadId, null, null); 

Function2(); 

caller.EndInvoke(out threadId, result); 

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

Структура вашего примера кода предполагает, что вы уже просмотрели Calling Synchronous Methods Asynchronously MSDN, но в случае, если у вас нет, я упомянул эту страницу, так как она включает в себя множество подробностей, которые помогут объяснить, как справиться с этим конкретный сценарий.

+1

Есть ли способ вызвать Function1 асинхронно, не используя метод BeginInvoke()? – IsaacBok

+1

Конечно. Фактически, использование 'BeginInvoke()', вероятно, является наименее распространенным способом, позволяющим выполнить метод асинхронно. Более типичным сегодня было бы завершение вызова в «Задаче». Например. 'Task task = Task.Run (() => Function1 (out threadId)); Function2(); task.Wait(); 'будет эквивалентом вышеупомянутого, но вместо этого использует' Task'. Обратите внимание, что для этого вам не нужно объявлять свой собственный тип делегата 'AsyncMethodCaller', поскольку метод вызывается непосредственно анонимным методом, а не является объектом экземпляра делегата. –

+0

Отлично! Спасибо вам, @Peter Duniho – IsaacBok

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