下面的代碼應該(至少在我看來)創建100個任務,這些任務都是並行等待的(這就是關於併發的觀點,對吧:D?),並且幾乎在同一時間完成。我猜想每個Task.Delay Timer對象都是在內部創建的。Task.Delay是否啓動一個新的線程?
public static async Task MainAsync() {
var tasks = new List<Task>();
for (var i = 0; i < 100; i++) {
Func<Task> func = async() => {
await Task.Delay(1000);
Console.WriteLine("Instant");
};
tasks.Add(func());
}
await Task.WhenAll(tasks);
}
public static void Main(string[] args) {
MainAsync().Wait();
}
但是!當我在Mono運行此我得到很奇怪的行爲:
- 的任務不會在同一時間完成,存在着巨大的延遲(大概在500-600ms)
- 在控制檯單顯示了很多創建的線程:
加載的程序集:/Users/xxxxx/Programming/xxxxx/xxxxxxxxxx/bin/Release/xxxxx.exe
開始線程:#2
主題開始: #3
線程開始:#4
線程開始:#5
線程開始:#6
線程開始:#7
線程完成:#3 < - 顯然1000毫秒的延遲完成?
線程完成:#2 < - 顯然延遲1000ms結束?
線程開始:#8
線程開始:#9
線程開始:#10
線程開始:#11
線程開始:#12
螺紋開始:#13
......你明白了。
這實際上是一個錯誤?或者我使用庫錯了?
[編輯] 我測試使用T定製的睡眠方法:
public static async Task MainAsync() {
Console.WriteLine("Started");
var tasks = new List<Task>();
for (var i = 0; i < 100; i++) {
Func<Task> func = async() => {
await SleepFast(1000);
Console.WriteLine("Instant");
};
tasks.Add(func());
}
await Task.WhenAll(tasks);
Console.WriteLine("Ready");
}
public static Task SleepFast(int amount) {
var source = new TaskCompletionSource<object>();
new Timer(state => {
var oldSrc = (TaskCompletionSource<object>)state;
oldSrc.SetResult(null);
}, source, amount, 0);
return source.Task;
}
這個時候,瞬間完成了所有的任務。所以我認爲這是一個非常糟糕的實現或錯誤。只是FYI:我已經在.NET上測試了使用Windows 8.1的原始代碼(使用Task.Delay),並且它按預期運行(1000個任務,等待1秒並行並完成)。
所以答案是:Mono的impl。 (某些)方法並不完美。一般來說,Task.Delay不會啓動線程,甚至很多線程都不應創建多個線程。
Task.Delay內部使用一個定時器,它在內部使用線程池。由於您目前正在快速創建100個任務,因此我猜測您的線程池中的線程已用完,因此會自動創建新線程。 – ken2k
所以定時器沒有使用可擴展的技術來實現?我希望有一些非常有效的東西。例如在node.js中,他們使用epoll(用於linux),我相信。 – Kr0e
每個任務之間500-600毫秒?你能發佈確切的時間嗎? –