Как создать метод async на С# 4 в соответствии с лучшими практиками?
Рассмотрим следующий фрагмент кода:
public static Task<string> FetchAsync()
{
string url = "http://www.example.com", message = "Hello World!";
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = WebRequestMethods.Http.Post;
return Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null)
.ContinueWith(t =>
{
var stream = t.Result;
var data = Encoding.ASCII.GetBytes(message);
Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, data, 0, data.Length, null, TaskCreationOptions.AttachedToParent)
.ContinueWith(t2 => { stream.Close(); });
})
.ContinueWith<string>(t =>
{
var t1 =
Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
.ContinueWith<string>(t2 =>
{
var response = (HttpWebResponse)t2.Result;
var stream = response.GetResponseStream();
var buffer = new byte[response.ContentLength > 0 ? response.ContentLength : 0x100000];
var t3 = Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null, TaskCreationOptions.AttachedToParent)
.ContinueWith<string>(t4 =>
{
stream.Close();
response.Close();
if (t4.Result < buffer.Length)
{
Array.Resize(ref buffer, t4.Result);
}
return Encoding.ASCII.GetString(buffer);
});
t3.Wait();
return t3.Result;
});
t1.Wait();
return t1.Result;
});
}
Он должен возвращать Task<string>
, отправлять HTTP POST-запрос с некоторыми данными, возвращать результат с веб-сервера в виде строки и быть максимально эффективным.
- Вы обнаружили какие-либо проблемы в отношении потока async в приведенном выше примере?
- Хорошо ли иметь .Wait() внутри .ContinueWith() в этом примере
- Вы видите какие-либо другие проблемы с этим спокойствием кода (сохраняя в настоящее время обработку исключений)?
Ответы
Ответ 1
Если связанный с асинхронным кодом С# 4.0 огромный и уродливый - есть вероятность, что он будет реализован правильно. Если это мило и коротко, то, скорее всего, это не так;)
.. Однако вы можете получить его более привлекательным, создав методы расширения на WebRequest, классы Stream и очистите основной метод.
PS: я надеюсь, что С# 5.0 с новым ключевым словом async
и библиотека будет выпущена в ближайшее время.
Ссылка: http://msdn.microsoft.com/en-us/vstudio/async.aspx
Ответ 2
Вы правы, думая, что Waits не нужны - результат будет блокироваться до тех пор, пока результат не будет готов.
Однако еще более простой способ заключается в том, чтобы использовать его в примерах, представленных в ParallelExtensionsExtras library.
Они сделали расширения для WebClient
, которые делают именно то, что вы ищете:
static Task<string> FetchAsync()
{
string url = "http://www.example.com", message = "Hello World!";
return new WebClient().UploadStringTask(url, "POST", message);
}
Подробнее об этом читайте в этой записи в параллельном программировании в блоге .NET.