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 ?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.03.14 06:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Например нужно считать данные из Stream, как известно за 1 Begin/End все данные могут не считаться и нужно проверять количество байт которые вернет End, если >0 то запустить повторно.


http://msdn.microsoft.com/en-us/library/system.io.stream.endread%28v=vs.110%29.aspx

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 Япония http://sams-tricks.blogspot.com
Дата: 16.03.14 07:10
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, samius, Вы писали:


А>В этой английской фразе написано — Возвращает 0 только в случае завершения потока, иначе блокируется пока хотя бы 1 байт не будет получен.

А>Откуда следует что не нужно повторять ?

Простите, перечитал исходный пост и увидел что вас интересует повтор операции в случае когда результат > 0. Т.е. я неверно вас понял и не то ответил.
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.03.14 07:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Например нужно считать данные из Stream, как известно за 1 Begin/End все данные могут не считаться и нужно проверять количество байт которые вернет End, если >0 то запустить повторно.


Извернуться именно с ContinueWith, наверное можно, но есть альтернативное решение.
Предлагаю создать MemoryStream, и выполнить stream.CopyToAsync.
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 16.03.14 08:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Не совсем понятно как это красиво изобразить в виде 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 )

Насколько я представляю то вот эта конструкция


   while ((bytesRead = await responseStream.ReadAsync(buf, 0, BufSize)) > 0)
    {
        result.AddRange(buf.Take(bytesRead));
        onProgress(result.Count);
    }


компилируется в нечто такое ( псевдокод )


   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 ?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 16.03.14 11:24
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Например нужно считать данные из 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#]

1) Используй async\await
2) Используй встроенный Stream.ReadAsync
3) Используй Stream.CopyAsync
4) Используй StreamReader.Read*Async
Re[2]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От: Аноним  
Дата: 16.03.14 11:47
Оценка:
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
Автор:
Дата: 16.03.14
).
Если такое увидеть в виде реальных Task, то думаю раскритикуют, await он конечно этот оверхед немного прячет, но от этого не легче.

Т.е. правильно я понимаю что старый добрый begin/end callback рационально никак не заменить Taskом ? чтоб без оверхедов ?
Re[3]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 16.03.14 12:39
Оценка: +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
Автор:
Дата: 16.03.14
).

Хрень полная.

А>Если такое увидеть в виде реальных 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
Автор:
Дата: 16.03.14
).

G>Хрень полная.

Можете привести пример как это разложили бы , хотелось бы сравнить.


А>>Если такое увидеть в виде реальных 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 Россия http://blog.gandjustas.ru/
Дата: 16.03.14 13:48
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, gandjustas, Вы писали:


А>>>Пример с async/await уже привели, но он мне кажется слишком тяжеловесным, если красивый await развернуть в то что реально компилится, таск в таксе и таском погоняет.

А>>>( http://rsdn.ru/forum/dotnet/5517474.1
Автор:
Дата: 16.03.14
).

G>>Хрень полная.

А>Можете привести пример как это разложили бы , хотелось бы сравнить.

http://msdn.microsoft.com/en-us/magazine/hh456403.aspx



А>>>Если такое увидеть в виде реальных 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 ?
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 16.03.14 18:27
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>компилируется в нечто такое ( псевдокод )


А>

А>   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 ?
От: Rinbe Россия  
Дата: 16.03.14 18:50
Оценка:
Делал в свое время на Bigin/End методах. Для передачи параметров и эксепшнов между вызовами методов использовал свою реализацию IAsyncResult.

С Task наверно похожим образом можно замутить. Я с ними не пока не работал.
Re[3]: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От: TK Лес кывт.рф
Дата: 16.03.14 20:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Пример с async/await уже привели, но он мне кажется слишком тяжеловесным, если красивый await развернуть в то что реально компилится, таск в таксе и таском погоняет.

А>( http://rsdn.ru/forum/dotnet/5517474.1
Автор:
Дата: 16.03.14
).

А>Если такое увидеть в виде реальных Task, то думаю раскритикуют, await он конечно этот оверхед немного прячет, но от этого не легче.

Накладные расходы на await сильно зависят от того, что именно надо "авейтить" — расходы могут быть более чем незначительными.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re: Task.FromAsync как продолжитьTask внутри ContinueWith ?
От: TK Лес кывт.рф
Дата: 16.03.14 20:52
Оценка:
Здравствуйте, Аноним, Вы писали:

А>// Так вот не понятно как повторить вызов taskRead, по идее к текущему Task как-то нужно добавить ContinueWith


Используйте TaskContinuationSource — все равно к кому делать ContinueWith главное, что-бы последний установил нужный результат
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.