2015-03-13 3 views
4

Я понимаю, что следующий плохая практика, так как он блокирует поток:TPL async ждет - асинхронная задача должна связать стек вызовов?

Task t = Task.Run(() => MyMethod()); 
t.Wait(); 

Хотя следующее не блокирует нить:

await MyMethod(); 

Однако использовать ждать, надо использовать ключевое слово async в сигнатуре метода и возвращает Task, а не пустоту, или Task<T>.

Однако в приложении N-Tier, если у вас есть огромный вызов в стек, то мы должны иметь каждый метод вызове асинхронной/Task, как показано на следующем простом примере из LINQPad:

async void Main() 
{ 
    int i = await GetNumberD(); 
    i.Dump(); 
} 

async Task<int> GetNumberD() 
{ 
    return await GetNumberC(); 
} 
async Task<int> GetNumberC() 
{ 
    return await GetNumberB(); 
} 
async Task<int> GetNumberB() 
{ 
    return await GetNumberA(); 
} 
async Task<int> GetNumberA() 
{ 
    await Task.Delay(TimeSpan.FromSeconds(1)); 
    return 7; 
} 
+2

Я не думаю, что вы понимаете, как работают асинхронные методы. Прочитайте эту вступительную статью https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_WhatHappensUnderstandinganAsyncMethod – Spo1ler

+1

Я думаю, что я совершенно ясно понимаю, как работает метод async. Я просто не понимаю, как это распространяется на стек вызовов и влияние на потоки в каждом вызывающем методе. Если бы вы могли ответить на мой комментарий к ответу Отиля ниже, я был бы очень благодарен. – DrGriff

ответ

2

Должен ли мы иметь каждый метод вызова async/Task?

Да, если метод, вызванный в конце стека, является асинхронным методом.

Обратите внимание, что документация посоветует, чтобы закончить название методов с суффиксом «асинхронного»:

async Task<int> GetNumberAsync() 
+0

Вправо - метод в нижней части стека представляет собой асинхронный метод. – DrGriff

+0

Итак, если этот метод в нижней части стека не возвращается сразу, то вызывающий поток возвращается в пул потоков до его завершения. И если каждый метод в стеке вызовов должен быть асинхронной задачей, тогда будет довольно много перераспределения потоков. Эффективным было бы то, что Thread 33 запускается в Main, проходит через методы D, C, B, а затем, когда он попадает в AWAIT, он возвращается в пул протектора. Затем поток 66 возвращается из A -> Main. Если каждый метод в стеке ожидает, то не будет ли задействовано еще много потоков? – DrGriff

+0

@DrGriff: то, что вы описали *, - это то, как «async' /' await »будет работать в этом сценарии (если нет специального контекста, такого как поток пользовательского интерфейса) - поток, вызывающий' Main', - это тот же самый поток, вызывающий 'Task .Delay', и поток, завершающий 'Task.Delay', является тем же самым потоком, который возобновляется' Main'. У меня есть ['async' intro blog post] (http://blog.stephencleary.com/2012/02/async-and-await.html), которые могут оказаться полезными. –

-1

Вы не и, пожалуйста, не делайте этого.

вы можете просто ждать Task.Run

await Task.Run(() => MyMethod());

async Task Main() 
{ 
    int i = await Task.Run(() => GetNumberD()); 
    i.Dump(); 
} 

int GetNumberD() 
{ 
    return GetNumberC(); 
} 
int GetNumberC() 
{ 
    return GetNumberB(); 
} 
int GetNumberB() 
{ 
    return GetNumberA(); 
} 
int GetNumberA() 
{ 
    return 7; 
} 

Я настоятельно рекомендую вам прочитать эту статью: http://blog.stephencleary.com/2013/10/taskrun-etiquette-and-proper-usage.html

EDIT Это не правильный ответ. В качестве комментариев я неверно истолковал задачу cpu bound.

+0

Что если 'GetNumberA()' вызывается в других местах? Должен ли он писать 'wait Task.Run (() => GetNumberA())' каждый раз? Разве не было бы проще и понятнее определить «GetNumberA()» как метод асинхронной работы? – Otiel

+0

это всегда зависит, но вы не должны использовать Task.Run в реализации. (Я думаю, вы можете иметь обертку, если хотите). Прочтите блог поэтапно, и вы поймете, почему. –

+1

Пункт моего вопроса состоял в том, что метод GetNumberA() делает что-то вроде загрузки чего-то из Интернета асинхронно, и поэтому должен иметь подпись: [async Task GetNumberA()]. Я только поставил Task.Delay (...), чтобы имитировать это. – DrGriff