Следующий код должен (по крайней мере, на мой взгляд) создать 100 Tasks
, которые все ожидают параллельно (что верно в отношении параллелизма, верно: D?) И завершаются почти одновременно. Я предполагаю, что для каждого Task.Delay
объект Timer
создается внутри.
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, я получаю очень странное поведение:
-
Tasks
не заканчиваются одновременно, есть огромные задержки (вероятно, около 500-600 мс) - В консоли моно показано множество созданных тем:
Загруженная сборка: /Users/xxxxx/Programming/xxxxx/xxxxxxxxxx/bin/Release/xxxxx.exe
Тема начата: # 2
Тема начата: # 3
Тема начата: # 4
Тема начата: # 5
Тема начата: # 6
Тема начата: # 7
Тема закончена: # 3 <- Очевидно, задержка в 1000 мс закончена?
Тема закончена: # 2 <- Очевидно, задержка в 1000 мс закончена?
Тема начата: # 8
Тема начата: # 9
Тема начата: # 10
Тема начата: # 11
Тема начата: # 12
Тема начата: # 13
... ты понял.
Это на самом деле ошибка? Или я неправильно использую библиотеку?
[РЕДАКТИРОВАТЬ] Я проверил пользовательский метод сна с использованием таймера:
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;
}
На этот раз все задачи выполнены мгновенно. Поэтому я считаю, что это действительно плохая реализация или ошибка.
[Edit2] Просто к сведению: я протестировал исходный код (с помощью Task.Delay
) в .NET, используя Windows 8.1, и теперь он работает как ожидалось (1000 Tasks
, ожидание в течение 1 секунды параллельно и завершение).
Таким образом, ответ: Mono Impl. из (некоторых) методов не идеален. В общем случае Task.Delay
не запускает поток, и даже многие из них не должны создавать несколько потоков.