[英]Why is non awaited Task blocking
我正在啟動 2 個任務,沒有await
它們,其中一個依賴於另一個。 我試圖理解為什么以下代碼阻塞被截斷。
public class Tasks {
EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.ManualReset);
public async Task Job1() {
Console.WriteLine("Finished job1");
handle.Set();
}
public async Task Job2() {
handle.WaitOne();
Console.WriteLine("Doing Job2 work");
}
}
class Program {
static async Task Main(string[] args) {
Tasks seq = new Tasks();
var t2 =seq.Job2();
var t1 =seq.Job1();
await Task.WhenAll(t1, t2);
Console.WriteLine("finished both");
}
}
如果我為我的兩個任務創建受CPU-bound
任務,它會起作用:
var t2=Task.Run(seq.Job2);
var t1=Task.Run(seq.Job1);
我還嘗試將這兩個任務放在與主線程不同的任務中,但它仍然阻塞:
var bigtask=Task.Run(async()=>{
var t2 =seq.Job2();
var t1 =seq.Job1();
});
如果我在不等待的情況下啟動一個任務,它與啟動一個新的CPU-bound
任務幾乎一樣嗎? ( Task.Run
)
看看你的編譯器警告; 他們會確切地告訴您出了什么問題。 具體來說,您使用的是沒有await
async
,因此這些方法將同步運行。
Task.Run
在線程池線程上執行該方法,這會阻止它同步運行。
如果我在不等待的情況下啟動任務,它與[使用 Task.Run] 幾乎不一樣嗎?
每個async
方法開始同步執行; await
是它可以異步運行的點。
async
本身不使用任何線程(或線程池); 它更像是一種更高級的回調語法。 Task.Run
確實使用線程池。
要解決您的潛在問題(讓一個任務等待另一個任務),最簡單的方法是將從Job1
返回的Task
Job1
給Job2
方法,並讓Job2
await
該任務。 如果這是不可能的,那么您需要一種異步信號(而不是像EventWaitHandle
這樣的阻塞信號)。 一次性異步信號是TaskCompletionSource<T>
; SemaphoreSlim
也支持異步等待; 更復雜的協調原語是我的AsyncEx 庫的一部分。
聲明方法“異步”不會自動使您的代碼成為多線程的。 您可以假設您的代碼將同步運行,直到“等待”某些東西。
這里的問題是 Job2 永遠不會返回,所以你的代碼會卡住。 但是,例如(而不是實際的解決方案),如果你做了這樣的事情:
public async Task Job2()
{
await Task.Delay(1000);
handle.WaitOne();
Console.WriteLine("Doing Job2 work");
}
您的程序實際上會退出,因為一旦等待延遲,該函數將變為異步並返回給調用者。
在 TPL(async/await) 中通常應該避免使用像“EventWaitHandle/ManualResetEvent”這樣的同步原語,因為它們在物理上阻塞了線程,而不是釋放它並等待回調。
這是一個實際的解決方案:
public class Tasks
{
SemaphoreSlim semaphore = new SemaphoreSlim(0);
public async Task Job1()
{
Console.WriteLine("Finished job1");
semaphore.Release();
}
public async Task Job2()
{
await semaphore.WaitAsync();
Console.WriteLine("Doing Job2 work");
}
}
class Program
{
static async Task Main(string[] args)
{
Tasks seq = new Tasks();
var t2 = seq.Job2();
var t1 = seq.Job1();
await Task.WhenAll(t1, t2);
Console.WriteLine("finished both");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.