考慮以下示例:
async Task DoWork()
{
await Task.Run(() =>
{
for (int i = 0; i < 25; i )
{
Console.WriteLine("Task run 1: " Thread.CurrentThread.ManagedThreadId);
}
});
// The SynchronizationContext.Post() gets called after Run 1 and before Run 2
await Task.Run(() =>
{
for (int i = 0; i < 25; i )
{
Console.WriteLine("Task run 2: " Thread.CurrentThread.ManagedThreadId);
}
});
// I expect it to run after Run 2 and before Run 3 as well but it doesn't
await Task.Run(() =>
{
for (int i = 0; i < 25; i )
{
Console.WriteLine("Task run 3: " Thread.CurrentThread.ManagedThreadId);
}
});
}
我希望SynchronizationContext.Post()每次等待操作結束時都會進行呼叫,但是在覆寫Post()這樣的操作之后
public class MySynchronizationContext
{
public override void Post(SendOrPostCallback d, object? state)
{
Console.WriteLine("Continuation: " Thread.CurrentThread.ManagedThreadId);
base.Post(d, state);
}
}
一開始就這樣安裝Main()
SynchronizationContext.SetSynchronizationContext(new MySynchronizationContext());
Run()在第一個完成后,它只列印一次訊息。
我認為這是因為Task.Run()可能會檢測到它在執行緒池執行緒上被呼叫并只是重用當前執行緒,但似乎并非如此,因為我的一些測驗導致Run 2和Run 3在不同的執行緒上運行。
為什么awaited 任務的完成只在第一個之后運行await?
uj5u.com熱心網友回復:
該SynchronizationContext.SetSynchronizationContext方法將提供的安裝SynchronizationContext在當前執行緒上。為了使SynchronizationContext后續 s 捕獲和重用相同await的內容, 的實作SynchronizationContext必須確保在原始執行緒上呼叫延續,或者將其自身安裝在用于呼叫延續的任何其他執行緒上。
您的實作 ( MySynchronizationContext) 沒有這樣做。它只是將Post呼叫委托給base.Post,這會呼叫ThreadPool. 該MySynchronizationContext實體未安裝在任何ThreadPool執行緒上,因此第二個await找不到要捕獲的內容,因此在方法完成的任何執行緒上呼叫第二個延續Task.Run,這也是一個ThreadPool執行緒。因此,基本上你得到的行為與使用正確實作SynchronizationContext的 . (如 Stephen Cleary 的AsyncContext) 并配置第一個await與ConfigureAwait(false).
uj5u.com熱心網友回復:
我最終自己弄清楚了。
問題似乎是我SynchronizationContext對await.
async Task DoWork()
{
// This is still in the main thread so SynchronizationContext.Current
// returns an instance of MySynchronizationContext which this
// await captures.
await Task.Run(() =>
{
for (int i = 0; i < 25; i )
{
Console.WriteLine("Task run 1: " Thread.CurrentThread.ManagedThreadId);
}
});
// Here it uses the captured MySynchronizationContext to call
// the .Post() method. The message gets printed to the console and
// continuation gets put on the ThreadPool
// This await tries to capture current SynchronizationContext but
// since we're on the ThreadPool's thread, SynchronizationContext.Current
// returns null and it uses the default implementation
// instead of MySynchronizationContext. This is why my message from
// the overriden .Post() doesn't get printed which made me believe
// that it didn't call .Post() at all. It did, just not my .Post()
await Task.Run(() =>
{
for (int i = 0; i < 25; i )
{
Console.WriteLine("Task run 2: " Thread.CurrentThread.ManagedThreadId);
}
});
// .Post() gets called on the default SynchronizationContext
// Again, we're on the ThreadPool's thread,
// so the default SynchronizationContext gets captured
await Task.Run(() =>
{
for (int i = 0; i < 25; i )
{
Console.WriteLine("Task run 3: " Thread.CurrentThread.ManagedThreadId);
}
});
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/432678.html
下一篇:如何實作執行緒安全的隨機
