Всем привет. Запутался немного в коде. Почему поток Main завершается до запуска этого кода ?
await Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(4000);
Console.WriteLine("Pavel");
});
Решил попробовать в Main приписать к вызову метода Math1 слово await но тогда код вообще не компилируется. А если его убрать, то выходит , что Main завершился мгновенно и дело не дошло до указанного выше блока кода. Привожу весь код
using System;
using System.Threading.Tasks;
class a
{
public async Task Meth1()
{
await Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(4000);
Console.WriteLine("Pavel");
});
}
}
class b
{
static void Main()
{
a A = new a();
await A.Meth1(); //без await сразу все завершается, с ним не компилится
}
}
Почему так происходит и как решить такую ситуацию ? Я ожидаю от кода такое поведение, что при вызове Meth1 Main ожидает пока в Meth1 выполнится лямбда
Ответ
Обновление. Начиная с C# 7.1, модификатор async можно использовать также и для функции Main. При этом неудобство, описанное ниже (отсутствует SynchronizationContext по умолчанию, а значит, код после await не будет возвращаться в исходный поток), остаётся.
Смотрите.
Если вы используете async/await, приложение командной строки — не лучший выбор. К сожалению, C# из коробки не поддерживает async для функции Main (обсуждение на гитхабе, вы можете тоже отписаться, чтобы было понятно, что эта фича нужна).
Поэтому вы должны писать что-то вроде такого:
class Program
{
static async Task AsyncMain(string[] args)
{
await Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(4000);
Console.WriteLine("Pavel");
});
}
static void Main(string[] args)
{
// синхронное ожидание!
AsyncMain(args).Wait();
}
}
Другая проблема состоит в том, что в приложениях командной строки нету SynchronizationContext'а, который мог бы «вернуть» выполнение в начальный поток. Потому что для этого нужен в той или иной форме аналог message loop'а, а у вас его нету. Таким образом, поведение программы будет отличаться от того, что обычно бывает в WPF/WinForms: код после await не будет возвращаться в исходный поток!
Как бороться с этим? Простейший обходной путь — можно тренироваться не на приложении командной строки, а на графическом приложении.
Более хороший путь — воспользоваться существующим message loop'ом. Например, так:
/*
Обвязочный код для использования async/await в консольных приложениях на C#
Создаёт SynchronizationContext, который возвращает async-вызовы в главный поток
(в отличие от стандартного контекста, который бы использовался в консольных приложениях)
Идея VladD, используйте и переделывайте как хотите. Никаких гарантий, разумеется.
Требует подключения WindowsBase.dll
*/
class Program
{
static async Task
[STAThread]
static int Main(string[] args)
{
int result = -1;
var dispatcher = Dispatcher.CurrentDispatcher;
dispatcher.BeginInvoke((Action)(() =>
{
AsyncMain(args).ContinueWith(asyncMain =>
{
if (!asyncMain.IsCanceled && !asyncMain.IsFaulted)
result = asyncMain.Result;
dispatcher.BeginInvokeShutdown(DispatcherPriority.ApplicationIdle);
},
TaskScheduler.FromCurrentSynchronizationContext());
}));
Dispatcher.Run();
return result;
}
}
Комментариев нет:
Отправить комментарий