# Async sequential workflows

DevFeed: [Async sequential workflows](<https://devfeed.tech/articles/async-sequential-workflows-38412.md>)

Original publisher: [Read original article](<https://khmylov.com/2012/04/async-sequential-workflows/>)

Author: Andrew Khmylov

Published: 2012-04-26T00:00:00Z

Content type: tutorial

Language: ru

Sources: [Despite the odds](<https://devfeed.tech/sources/despite-the-odds.md>)

Topics: [async](<https://devfeed.tech/topics/async.md>), [async/await](<https://devfeed.tech/topics/async-await.md>), [client](<https://devfeed.tech/topics/client.md>), [.NET](<https://devfeed.tech/topics/net.md>)

Tags: [async](<https://devfeed.tech/tags/async.md>), [await](<https://devfeed.tech/tags/await.md>), [client](<https://devfeed.tech/tags/client.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [foreach](<https://devfeed.tech/tags/foreach.md>), [observable](<https://devfeed.tech/tags/observable.md>), [request](<https://devfeed.tech/tags/request.md>), [yield](<https://devfeed.tech/tags/yield.md>)

## AI overview

This tutorial compares synchronous and asynchronous implementations of sequential workflows for downloading files with .NET WebClient. It explains how sequential requests can be represented with observables and how async/await can reduce the work needed to describe the control flow.

## Source excerpt

В последнее время всё чаще приходится сталкиваться с задачами, требующими выполнения последовательных асинхронных операций. Примером может служить загрузка файлов на мобильном устройстве. Учитывая что телефон может работать на слабом мобильном соединении, нам вряд ли удастся получить прирост производительности от параллельной загрузки. Да и стандартный класс WebClient, представленный в BCL не очень дружит с concurrent operations (точнее вообще не дружит). Создавать новый экземпляр на каждый запрос кажется идейно неправильным, так что попробуем обойтись одним веб-клиентом, обрабатывающим множество последовательных запросов. Для начала - тривиальная синхронная реализация (которая конечно же не будет работать на WP7 из-за отсутствия синхронных методов у WebClient'а): public IEnumerable<string> Handle(IEnumerable<Uri> requests) { var client = new WebClient(); foreach (var request in requests) { yield return client.DownloadString(request); } } Разработчику, использующему асинхронную версии, скорее всего захочется узнать о моменте завершении загрузок. Не будем плохими мальчиками/девочками и отбросим мысли о EAP и ручном CPS. Довольно очевидным решением будет представить наши ожидающие загрузки файлы в виде потока событий при помощи observables. К сожалению, WebClient использует EAP для своих асинхронных операций, поэтому код становится чуть более неопрятным: public IObservable<string> HandleAsync(IList<Uri> requests) { var client = new WebClient(); var subject = new Subject<string>(); var enumerator = requests.GetEnumerator(); Action takeNext = () => { if (enumerator.MoveNext()) { client.DownloadStringAsync(enumerator.Current); } else { subject.OnCompleted(); } }; client.DownloadStringCompleted += (s, e) => { if (e.Error != null) { subject.OnError(e.Error); } else { subject.OnNext(e.Result); takeNext(); } }; takeNext(); return subject; } В обоих случаях мы по сути описываем корутины, передающие управление в момент окончания обработки запроса. В синхронной реализации компи