Я не вижу различий между новыми функциями async С# (и VB) и .NET 4.0 Параллельная библиотека задач. Возьмем, к примеру, код Эрика Липперта отсюда:
async void ArchiveDocuments(List<Url> urls) {
Task archive = null;
for(int i = 0; i < urls.Count; ++i) {
var document = await FetchAsync(urls[i]);
if (archive != null)
await archive;
archive = ArchiveAsync(document);
}
}
Кажется, что ключевое слово await
выполняет две разные цели. Первое вхождение (FetchAsync
), по-видимому, означает: "Если это значение используется позже в методе, и его задача еще не закончена, подождите, пока она не завершится до продолжения". Второй экземпляр (archive
), по-видимому, означает: "Если эта задача еще не закончена, подождите прямо сейчас, пока она не завершится". Если я ошибаюсь, пожалуйста, исправьте меня.
Не так ли легко написать так?
void ArchiveDocuments(List<Url> urls) {
for(int i = 0; i < urls.Count; ++i) {
var document = FetchAsync(urls[i]); // removed await
if (archive != null)
archive.Wait(); // changed to .Wait()
archive = ArchiveAsync(document.Result); // added .Result
}
}
Я заменил первый await
на Task.Result
, где действительно нужно значение, а второе await
с Task.Wait()
, где на самом деле происходит ожидание. Функциональность (1)
уже реализована, а (2)
гораздо ближе семантически к тому, что на самом деле происходит в коде.
Я понимаю, что метод async
перезаписывается как конечный автомат, похожий на итераторы, но я также не вижу, какие выгоды приносят. Любой код, которому требуется другой поток для работы (например, загрузка), по-прежнему будет нуждаться в другом потоке, а любой код, который не работает (например, чтение из файла), все еще может использовать TPL для работы только с одним потоком.
Мне явно не хватает чего-то огромного здесь; может ли кто-нибудь помочь мне понять это немного лучше?