Task.FromAsync как продолжитьTask внутри ContinueWith ?
От:
Аноним
Дата:
16.03.14 06:47
Оценка:
Например нужно считать данные из Stream, как известно за 1 Begin/End все данные могут не считаться и нужно проверять количество байт которые вернет End, если >0 то запустить повторно.
Не совсем понятно как это красиво изобразить в виде Task
Задача по идее уже 100 раз решенная но что-то ответ с ходу не нашелся.
class TaskState
{
public byte[] readBuffer;
public List<byte> response;
public TaskState()
{
readBuffer = new byte[4000];
response = new List<byte>();
}
}
static void Main( string[] args )
{
var request = HttpWebRequest.Create("http://ya.ru" );
var stream = request.GetResponseStream();
var state = new TaskState();
var taskRead = Task.TaskFactory.FromAsync<int>( stream.BeginRead, stream.EndRead, state.readBuffer,0, state.readBuffer.Length, state );
taskRead.ContinueWith( (t)=>
{
if ( t.Result > 0 )
{
// Так вот не понятно как повторить вызов taskRead, по идее к текущему Task как-то нужно добавить ContinueWith
}
}
....
}
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>Например нужно считать данные из Stream, как известно за 1 Begin/End все данные могут не считаться и нужно проверять количество байт которые вернет End, если >0 то запустить повторно.
Streams return zero (0) only at the end of the stream, otherwise, they should block until at least one byte is available.
Т.е. смысла повторять операцию нет.
Re[2]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От:
Аноним
Дата:
16.03.14 07:05
Оценка:
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Аноним, Вы писали:
А>>Например нужно считать данные из Stream, как известно за 1 Begin/End все данные могут не считаться и нужно проверять количество байт которые вернет End, если >0 то запустить повторно.
S>http://msdn.microsoft.com/en-us/library/system.io.stream.endread%28v=vs.110%29.aspx S>
S>Streams return zero (0) only at the end of the stream, otherwise, they should block until at least one byte is available.
S>Т.е. смысла повторять операцию нет.
В этой английской фразе написано — Возвращает 0 только в случае завершения потока, иначе блокируется пока хотя бы 1 байт не будет получен.
Откуда следует что не нужно повторять ?
Re[3]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, samius, Вы писали:
А>В этой английской фразе написано — Возвращает 0 только в случае завершения потока, иначе блокируется пока хотя бы 1 байт не будет получен. А>Откуда следует что не нужно повторять ?
Простите, перечитал исходный пост и увидел что вас интересует повтор операции в случае когда результат > 0. Т.е. я неверно вас понял и не то ответил.
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>Например нужно считать данные из Stream, как известно за 1 Begin/End все данные могут не считаться и нужно проверять количество байт которые вернет End, если >0 то запустить повторно.
Извернуться именно с ContinueWith, наверное можно, но есть альтернативное решение.
Предлагаю создать MemoryStream, и выполнить stream.CopyToAsync.
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>Не совсем понятно как это красиво изобразить в виде Task А>Задача по идее уже 100 раз решенная но что-то ответ с ходу не нашелся.
const int BufSize = 0x10;
static async Task<List<byte>> ReadYaRuAsync(Action<int> onProgress)
{
var result = new List<byte>();
var request = (HttpWebRequest)WebRequest.Create("http://ya.ru");
var responseStream = (await request.GetResponseAsync()).GetResponseStream();
var buf = new byte[BufSize];
int bytesRead;
while ((bytesRead = await responseStream.ReadAsync(buf, 0, BufSize)) > 0)
{
result.AddRange(buf.Take(bytesRead));
onProgress(result.Count);
}
return result;
}
static void Main(string[] args)
{
try
{
var response = ReadYaRuAsync(Console.WriteLine).Result;
Console.WriteLine("{0} total bytes read", response.Count);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
Re[2]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От:
Аноним
Дата:
16.03.14 11:15
Оценка:
Здравствуйте, scale_tone, Вы писали:
_>Здравствуйте, Аноним, Вы писали:
А>>Не совсем понятно как это красиво изобразить в виде Task А>>Задача по идее уже 100 раз решенная но что-то ответ с ходу не нашелся.
_>
_>const int BufSize = 0x10;
_>static async Task<List<byte>> ReadYaRuAsync(Action<int> onProgress)
_>{
_> var result = new List<byte>();
_> var request = (HttpWebRequest)WebRequest.Create("http://ya.ru");
_> var responseStream = (await request.GetResponseAsync()).GetResponseStream();
_> var buf = new byte[BufSize];
_> int bytesRead;
_> while ((bytesRead = await responseStream.ReadAsync(buf, 0, BufSize)) > 0)
_> {
_> result.AddRange(buf.Take(bytesRead));
_> onProgress(result.Count);
_> }
_> return result;
_>}
_>static void Main(string[] args)
_>{
_> try
_> {
_> var response = ReadYaRuAsync(Console.WriteLine).Result;
_> Console.WriteLine("{0} total bytes read", response.Count);
_> }
_> catch (Exception ex)
_> {
_> Console.WriteLine(ex);
_> }
_> Console.ReadKey();
_>}
_>
спасибо за пример, но все же, интересует как это делается с помощью Task ( framework 4.0 )
int bytesRead = 0;
while ( bytesRead != 0 )
{
task = responseStream.ReadAsync(buf,0,BufSize)
var bytesRead = task.ContinueWith( t =>
{
result.Add(t.Result)
});
task.Wait();
}
т.е. постоянное создание task, ожидание завершения, в общем куча бесполезной работы, имхо лучше уж тогда использовать BeginXXX/EndXXX с Callback будет оптимальнее.
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>Например нужно считать данные из Stream, как известно за 1 Begin/End все данные могут не считаться и нужно проверять количество байт которые вернет End, если >0 то запустить повторно. А>Не совсем понятно как это красиво изобразить в виде Task А>Задача по идее уже 100 раз решенная но что-то ответ с ходу не нашелся.
А>static void Main( string[] args ) А>{
А> var request = HttpWebRequest.Create("http://ya.ru" );
А> var stream = request.GetResponseStream();
А> var state = new TaskState();
А> var taskRead = Task.TaskFactory.FromAsync<int>( stream.BeginRead, stream.EndRead, state.readBuffer,0, state.readBuffer.Length, state );
А> taskRead.ContinueWith( (t)=> А> { А> if ( t.Result > 0 ) А> { А> // Так вот не понятно как повторить вызов taskRead, по идее к текущему Task как-то нужно добавить ContinueWith А> }
А> }
А> .... А>} А>[/c#]
Т.е. в 4м фреймоврке это нормально никак не сделать ?
Пример с async/await уже привели, но он мне кажется слишком тяжеловесным, если красивый await развернуть в то что реально компилится, таск в таксе и таском погоняет.
( http://rsdn.ru/forum/dotnet/5517474.1
G>>1) Используй async\await G>>2) Используй встроенный Stream.ReadAsync G>>3) Используй Stream.CopyAsync G>>4) Используй StreamReader.Read*Async
А>Т.е. в 4м фреймоврке это нормально никак не сделать ?
"Это" что?
А>Пример с async/await уже привели, но он мне кажется слишком тяжеловесным, если красивый await развернуть в то что реально компилится, таск в таксе и таском погоняет. А>( http://rsdn.ru/forum/dotnet/5517474.1
).
Хрень полная.
А>Если такое увидеть в виде реальных Task, то думаю раскритикуют, await он конечно этот оверхед немного прячет, но от этого не легче.
Самое главное что делает await — разворачивает линейный код в цепочку вызовов continuation. Сделать тоже руками — сложно.
А>Т.е. правильно я понимаю что старый добрый begin/end callback рационально никак не заменить Taskом ? чтоб без оверхедов ?
Таски проще Begin\End, самое сложное — control flow.
Напиши полный пример с APM, а потом пары вызовов Begin\End замени на Task+ContinueWith.
Re[4]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От:
Аноним
Дата:
16.03.14 13:02
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Аноним, Вы писали:
G>>>1) Используй async\await G>>>2) Используй встроенный Stream.ReadAsync G>>>3) Используй Stream.CopyAsync G>>>4) Используй StreamReader.Read*Async
А>>Т.е. в 4м фреймоврке это нормально никак не сделать ?
G>"Это" что?
Работу через Task. Без Async фич которые в 4.5 появились ( да и с ними рисуйте не async/await а в то что это в итоге раскладывается чтобы оверхед был виден )
А>>Пример с async/await уже привели, но он мне кажется слишком тяжеловесным, если красивый await развернуть в то что реально компилится, таск в таксе и таском погоняет. А>>( http://rsdn.ru/forum/dotnet/5517474.1
Можете привести пример как это разложили бы , хотелось бы сравнить.
А>>Если такое увидеть в виде реальных Task, то думаю раскритикуют, await он конечно этот оверхед немного прячет, но от этого не легче. G>Самое главное что делает await — разворачивает линейный код в цепочку вызовов continuation. Сделать тоже руками — сложно.
Да но он автоматом не делает количество Continuation нужным, в приведенном ранее примере там в цикле делается await, т.е. по сути каждую итерацию цикла ReadAsync создает таск, ожидает его завершения проверяет количество байт которое этот таск загрузил и так повторяется каждую итерацию цикла.
А>>Т.е. правильно я понимаю что старый добрый begin/end callback рационально никак не заменить Taskом ? чтоб без оверхедов ? G>Таски проще Begin\End, самое сложное — control flow.
G>Напиши полный пример с APM, а потом пары вызовов Begin\End замени на Task+ContinueWith.
Не совсем понял что значит АРМ.
Re[5]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, gandjustas, Вы писали:
А>>>Пример с async/await уже привели, но он мне кажется слишком тяжеловесным, если красивый await развернуть в то что реально компилится, таск в таксе и таском погоняет. А>>>( http://rsdn.ru/forum/dotnet/5517474.1
А>>>Если такое увидеть в виде реальных Task, то думаю раскритикуют, await он конечно этот оверхед немного прячет, но от этого не легче. G>>Самое главное что делает await — разворачивает линейный код в цепочку вызовов continuation. Сделать тоже руками — сложно.
А>Да но он автоматом не делает количество Continuation нужным.
Как раз делает, октрой код рефлектором и посмотри.
А>в приведенном ранее примере там в цикле делается await, т.е. по сути каждую итерацию цикла ReadAsync создает таск, ожидает его завершения проверяет количество байт которое этот таск загрузил и так повторяется каждую итерацию цикла.
Самое интересное как сделать цикл когда код не линейный, а цепочка продолжений.
А>>>Т.е. правильно я понимаю что старый добрый begin/end callback рационально никак не заменить Taskом ? чтоб без оверхедов ? G>>Таски проще Begin\End, самое сложное — control flow.
G>>Напиши полный пример с APM, а потом пары вызовов Begin\End замени на Task+ContinueWith.
А>Не совсем понял что значит АРМ.
APM — это паттерн BeginXXX\EndXXX и IAsyncResult.
Re[3]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>компилируется в нечто такое ( псевдокод )
А>
А> int bytesRead = 0;
А> while ( bytesRead != 0 )
А> {
А> task = responseStream.ReadAsync(buf,0,BufSize)
А> var bytesRead = task.ContinueWith( t =>
А> {
А> result.Add(t.Result)
А> });
А> task.Wait();
А> }
А>
Нет. Оно компилируется в нечто другое. Вы неправильно представляете себе работу async/await.
В Вашей задаче нужно выстроить цепочку тасков заранее неизвестной длины, и при этом сохранить контроль над ее концом (Вы же не из научного интереса скачиваете ya.ru, Вам потом со скачанными байтами что-то полезное сделать нужно, так ведь?). Без async/await задача "изящно" не решается и требует организации собственного велосипедного async/await.
А при таком уровне обеспокоенности оверхедом Вам скорее на какой-нибудь этот форум надо...
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
Здравствуйте, Аноним, Вы писали:
А>Пример с async/await уже привели, но он мне кажется слишком тяжеловесным, если красивый await развернуть в то что реально компилится, таск в таксе и таском погоняет. А>( http://rsdn.ru/forum/dotnet/5517474.1