Давайте отрисуем ваш код!
Это один остается, как это было
static void Main(string[] args)
{
Test();
Console.WriteLine("Main Thread Id :{0}", Thread.CurrentThread.ManagedThreadId);
Console.Read();
}
Это метод асинхронной. Более конкретно, это асинхронный метод, который является своего рода неуклюжим; вы скоро увидите разницу. Как обычный метод, это выглядит следующим образом:
static void Test()
{
Console.WriteLine("before wait Current Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);
Task getnameresult = GetName();
Action<Task> continuation = (task) => {
Console.WriteLine("after wait Current Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);
}
Task continuationresult = getnameresult.ContinueWith(continuation);
//you are guaranteed that continuation will run on some (unspecified) thread after the taskgetnameresult completes
return;
//note that we do nothing with continuationresult, not even return it, so there is no way to know if it has completed.
}
И GetName
становится
static Task GetName()
{
return Task.Run(() =>
{
Console.WriteLine("Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("In antoher thread.....");
});
}
методы, которые устанавливают свой asynchronity здесь Task.ContinueWith: https://msdn.microsoft.com/en-us/library/dd270696%28v=vs.110%29.aspx и Task.Run: https://msdn.microsoft.com/en-us/library/hh195051%28v=vs.110%29.aspx
Ни один из этих методов не говорит много о потоках, просто чтобы они могли запускаться несинхронно. Время выполнения может и будет планировать их по своему усмотрению. Любые знания о том, как это работает, следует рассматривать как деталь реализации, и вы должны предположить, что это может различаться при каждом запуске приложения (и это будет отличаться, как указывают некоторые другие ответы в консольном приложении или приложении WPF)
Так что здесь происходит. Ну, во-первых, Main
позвонит Test()
. Test
сначала напечатает сообщение «before wait Current Thread Id». Затем он вызывает GetName()
Этот метод планирует действие, которое будет выполняться в каком-то неуказанном потоке в какое-то неопределенное время в будущем, которое будет печатать «Current Thread Id» и «В другом потоке .....» и возвращает задача, представляющая это действие, возвращая управление обратно на Test
Test
теперь создаст новую задачу, которая будет в другое время в будущем, но определенно после возвращенной задачи напечатать сообщение «после ожидания Текущая тема ID "и обратный контроль до Main
. Main
теперь заблокирует поток, пока он не прочитает что-то из консоли.
Итак, давайте все вместе. Мы точно знаем, что сначала печатается «до ожидания», что является простым синхронным вызовом.
Затем мы знаем, что после этого будет напечатана строка «Текущий поток» и будет напечатана строка «Основной поток», но мы не дали никаких обещаний относительно порядка, в котором они будут выполняться, или если они могут даже работать одновременно.
В вашей ситуации среда выполнения определяет, что она выполнит задачу, которая сначала печатает строку «Текущий поток». Зачем? Причины. SynchronisationContext
s. Но самое главное, вещи, которые вы не должны заботиться. Когда вы программируете асинхронно, вы отказываетесь от контроля над тем, что работает первым, и тем, что работает дальше.
Тогда то же самое происходит и для следующего продолжения. Не существует внутренней связи между тем, когда печатается «Идентификатор основного потока», и когда печатается «После ожидания», только после того, как печатается строка «Текущий поток», должна появиться только «После ожидания».
Выполняя действия асинхронно, вы сообщаете время выполнения, которое вам не важно, в каком порядке выполняются действия. Попытка рассуждать о том, что будет происходить, перед чем другая вещь после того, как вы сказали на том, что вам особенно неинтересно, какой порядок они бегут в границах безумия.
[Лучшие практики в программировании асинхронного программирования] (https://msdn.microsoft.com/en-us/magazine/jj991977.aspx): «Методы асинхронного вывода, имеющие Void, имеют определенную цель: сделать асинхронные обработчики событий возможными. Чтобы обобщить это первое руководство, вы должны предпочесть async Task для async void " –
Обратите внимание на то, что соглашение об именах для методов async суффиксное имя' Async', поэтому ваши методы могут быть переименованы в 'TestAsync' и' GetNameAsync'. – Default