BeginAsync vs Tasks
От: Аноним  
Дата: 14.02.14 23:29
Оценка:
Например Http запрос

1) можно сделать через BeginSend, BeginGetResponse.
как это описано здесь
http://msdn.microsoft.com/en-us/library/86wf6409(v=vs.110).aspx


2) можно сделать синхронный http запрос, но вызывать его через Task.

Мне кажется второй способ более простой и удобнее для чтения отладки и т.п.
Есть ли какая-то эффективность у 1го способа или это уже можно считать как устаревший подход ?
Re: BeginAsync vs Tasks
От: TK Лес кывт.рф
Дата: 15.02.14 14:40
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>2) можно сделать синхронный http запрос, но вызывать его через Task.

А>Мне кажется второй способ более простой и удобнее для чтения отладки и т.п.
А>Есть ли какая-то эффективность у 1го способа или это уже можно считать как устаревший подход ?

Сделайте через Task.FromAsync
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: BeginAsync vs Tasks
От: Аноним  
Дата: 15.02.14 17:55
Оценка:
Здравствуйте, TK, Вы писали:

TK>Здравствуйте, Аноним, Вы писали:


А>>2) можно сделать синхронный http запрос, но вызывать его через Task.

А>>Мне кажется второй способ более простой и удобнее для чтения отладки и т.п.
А>>Есть ли какая-то эффективность у 1го способа или это уже можно считать как устаревший подход ?

TK>Сделайте через Task.FromAsync

А смысл ? Зачем ? Почему бы синхронный метод не выполНить в таске проще ведь
Re[3]: BeginAsync vs Tasks
От: fddima  
Дата: 15.02.14 20:08
Оценка: +1
Здравствуйте, Аноним, Вы писали:

TK>>Сделайте через Task.FromAsync

А>А смысл ? Зачем ? Почему бы синхронный метод не выполНить в таске проще ведь
Какой смысл выполнять "асинхронный" метод в "таске". Налицо каша в голове. Или разберись как оно таки устроено, или твой вопрос не понят, и задай его заново.
Re[4]: BeginAsync vs Tasks
От: Аноним  
Дата: 15.02.14 20:36
Оценка:
Здравствуйте, fddima, Вы писали:

F>Здравствуйте, Аноним, Вы писали:


TK>>>Сделайте через Task.FromAsync

А>>А смысл ? Зачем ? Почему бы синхронный метод не выполНить в таске проще ведь
F> Какой смысл выполнять "асинхронный" метод в "таске". Налицо каша в голове. Или разберись как оно таки устроено, или твой вопрос не понят, и задай его заново.
А где ты увидел что я предлагаю асинхронный метод в таске выполнять ?
Я предлагаю синхронный метод выполнять в таске, вместо асинхронного патерна ( п1. в исходном топике ) и спрашиваю в чем преимущество п.1. если оно есть
Re[5]: BeginAsync vs Tasks
От: Tom Россия http://www.RSDN.ru
Дата: 15.02.14 21:12
Оценка: +1
Здравствуйте, Аноним, Вы писали:

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


F>>Здравствуйте, Аноним, Вы писали:


TK>>>>Сделайте через Task.FromAsync

А>>>А смысл ? Зачем ? Почему бы синхронный метод не выполНить в таске проще ведь
F>> Какой смысл выполнять "асинхронный" метод в "таске". Налицо каша в голове. Или разберись как оно таки устроено, или твой вопрос не понят, и задай его заново.
А>А где ты увидел что я предлагаю асинхронный метод в таске выполнять ?
А>Я предлагаю синхронный метод выполнять в таске, вместо асинхронного патерна ( п1. в исходном топике ) и спрашиваю в чем преимущество п.1. если оно есть
Если на эффективность посрать то можно и синхронный вахов делать асинхронно.
Разница лишь в том что при использовании асинхронного вызова, во время самого вызова не будет задействован поток.
Если вызов синхронный то поток, будь то поток пула или поток пользовательский будет ждать окончания вызова.
Для 99% задач на эффективность пофигу, разница может быть только для серверных приложений либо для слабых девасов, и то если вряд ли.
Народная мудрось
всем все никому ничего(с).
Re[6]: BeginAsync vs Tasks
От: Аноним  
Дата: 16.02.14 03:43
Оценка:
А>>Я предлагаю синхронный метод выполнять в таске, вместо асинхронного патерна ( п1. в исходном топике ) и спрашиваю в чем преимущество п.1. если оно есть
Tom>Если на эффективность посрать то можно и синхронный вахов делать асинхронно.
Tom>Разница лишь в том что при использовании асинхронного вызова, во время самого вызова не будет задействован поток.
А как тогда по вашему работает асинхронный вызов ? Какой механизм позволяет ждать ответа от сервера и вызывать callback ?

Можно легко проверить — потоки разные, т.е. на асинхронный callback также создается поток.
        static void Main(string[] args)
        {
            
            Console.WriteLine("Main Thread : {0}", Thread.CurrentThread.ManagedThreadId);
            var httpRequest = HttpWebRequest.Create("http://rsdn.ru");
            httpRequest.BeginGetResponse((ar)=>
                {
                    Console.WriteLine("Callback Thread : {0}", Thread.CurrentThread.ManagedThreadId);
                }, null);

            Console.ReadKey();
        }



Tom>Если вызов синхронный то поток, будь то поток пула или поток пользовательский будет ждать окончания вызова.

Tom>Для 99% задач на эффективность пофигу, разница может быть только для серверных приложений либо для слабых девасов, и то если вряд ли.
Re[7]: BeginAsync vs Tasks
От: k.o. Россия  
Дата: 16.02.14 07:29
Оценка:
Здравствуйте, Аноним, Вы писали:

А>>>Я предлагаю синхронный метод выполнять в таске, вместо асинхронного патерна ( п1. в исходном топике ) и спрашиваю в чем преимущество п.1. если оно есть

Tom>>Если на эффективность посрать то можно и синхронный вахов делать асинхронно.
Tom>>Разница лишь в том что при использовании асинхронного вызова, во время самого вызова не будет задействован поток.
А>А как тогда по вашему работает асинхронный вызов ? Какой механизм позволяет ждать ответа от сервера и вызывать callback ?
I/O Completion Ports

А>Можно легко проверить — потоки разные, т.е. на асинхронный callback также создается поток.

В том-то и дело, что поток создается (берется из пула) для вызова callback, а не для самого запроса.
Re[8]: BeginAsync vs Tasks
От: Аноним  
Дата: 16.02.14 08:10
Оценка: -1
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Аноним, Вы писали:


А>>>>Я предлагаю синхронный метод выполнять в таске, вместо асинхронного патерна ( п1. в исходном топике ) и спрашиваю в чем преимущество п.1. если оно есть

Tom>>>Если на эффективность посрать то можно и синхронный вахов делать асинхронно.
Tom>>>Разница лишь в том что при использовании асинхронного вызова, во время самого вызова не будет задействован поток.
А>>А как тогда по вашему работает асинхронный вызов ? Какой механизм позволяет ждать ответа от сервера и вызывать callback ?
KO>I/O Completion Ports

А>>Можно легко проверить — потоки разные, т.е. на асинхронный callback также создается поток.

KO>В том-то и дело, что поток создается (берется из пула) для вызова callback, а не для самого запроса.

Тоже легко проверить что это утверждение неверно, новые потоки появляются сразу после вызова BeginGetResponse
        static void Main(string[] args)
        {
            
            Console.WriteLine("Main Thread : {0}", Thread.CurrentThread.ManagedThreadId);
            var httpRequest = HttpWebRequest.Create("http://rsdn.ru");
            Console.WriteLine("Threads before async call :{0}",Process.GetCurrentProcess().Threads.Count);
            httpRequest.BeginGetResponse((ar)=>
                {
                    Console.WriteLine("Threads in callback : {0}", Process.GetCurrentProcess().Threads.Count);
                    Console.WriteLine("Callback Thread : {0}", Thread.CurrentThread.ManagedThreadId);
                }, null);
            Console.WriteLine("Threads after async call :{0}", Process.GetCurrentProcess().Threads.Count);
            Console.ReadKey();
        }


Так же если посмотреть реализацию IO Ports как это обычно реализуется , то видно что реализуется она через создание пула потоков.

[c#]
http://habrahabr.ru/post/59282/

HANDLE iocp=CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
создаст новый объект порта завершения и вернет нам его хендл. Здесь в качестве первого аргумента передается значение INVALID_HANDLE_VALUE, которое и означает то, что нам нужен новый порт. Следующие два аргумента должны иметь значение 0. При создании можно указать сколько потоков одновременно смогут работать для этого порта с помощью последнего аргумента. Если указать 0, то будет использовано значение, равное количеству процессоров в системе.

Следующим шагом является создание потоков, которые будут задействованы в пуле. Тут нельзя дать универсального совета. Некоторые говорят, что потоков должно быть в два раза больше процессоров в системе, другие, что их количество должно быть равно, третьи динамически изменяют размеры пула. Как тут поступить зависит от приложения и конфигурации компьютера. У меня старенький пенек с HyperThreading, поэтому система видит мой процессор как два. По этой причине в моем примере будет 2 рабочих потока в пуле.

for(int i=1;i<=2;i++) { HANDLE hWorking=CreateThread(0,0,(LPTHREAD_START_ROUTINE)&WorkingThread,iocp,0,0); CloseHandle(hWorking); }
[/q]
Re: BeginAsync vs Tasks
От: dsorokin Россия  
Дата: 16.02.14 10:19
Оценка:
Устаревшие подходы? Возможно, что оба) По мне так самая простая и логичная вещь — это F# async workflow. Все остальное какое-то мутное и притянутое за уши) И да, если что, то я много раз видел в рефлекторе, во что превращается вычисление Async<'a>, и как оно проходит квази-цитирование. Надеюсь, что удалось пошутить, хотя сейчас я был и вполне серьезен тоже)
Re[9]: BeginAsync vs Tasks
От: Tom Россия http://www.RSDN.ru
Дата: 16.02.14 10:55
Оценка: +5
А>Тоже легко проверить что это утверждение неверно, новые потоки появляются сразу после вызова BeginGetResponse
Вы не правильно проверяете.
То что поток создался в пуле это вполне нормально.
Главное что ы во время того как работает BeginGetResponse поток в пуле не использовался.
Народная мудрось
всем все никому ничего(с).
Re: BeginAsync vs Tasks
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 16.02.14 12:04
Оценка: 22 (3) +1
Здравствуйте, Аноним, Вы писали:

А>Мне кажется второй способ более простой и удобнее для чтения отладки и т.п.

А>Есть ли какая-то эффективность у 1го способа или это уже можно считать как устаревший подход ?

На нынешнем этапе развития науки и техники устаревшим считается скорее второй подход.

Во всех трех вариантах:

1) Begin/End-методы,
2) обертка Task.FromAsync над ними, упомянутая TK
Автор: TK
Дата: 15.02.14

и
3) синхронные сетевые вызовы в теле таски,

непосредственно вызовы и ожидания ответов действительно происходят в потоках из IO-пула. Но вариант №3 потребляет _еще_один_ поток, в дополнение к уже потребляемым IO-потокам. Т.е. в общем случае требует в два раза больше потоков (=> в два раза больше памяти) и рано или поздно упрется в лимит на их число.

Преимущества первых двух вариантов над третьим особенно хорошо видны, если принудительно ограничить размер ThreadPool-а:

class Program
{
    const int CallCount = 30;
    // this service method sleeps for 1 second and returns some JSON
    const string LongMethodUri = "http://beginendtasktest.azurewebsites.net/api/values";

    static void Main()
    {
        // limiting the thread pool size
        ThreadPool.SetMinThreads(3, 3);
        ThreadPool.SetMaxThreads(3, 3);

        Measure(BeginEndTest);
        Measure(TaskFromAsyncTest);
        Measure(SynchronousTaskTest);

        int workerThreads, ioThreads;
        ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);
        Console.WriteLine("Worker threads: {0}, IO threads: {1}", workerThreads, ioThreads);
        Console.WriteLine("Any key press you...");
        Console.ReadKey();
    }

    static void Measure(Action todo)
    {
        var sw = new Stopwatch();
        sw.Start();
        todo();
        sw.Stop();
        Console.WriteLine("{0} took {1} ms", todo.Method.Name, sw.ElapsedMilliseconds);
    }

    static void BeginEndTest()
    {
        var asyncResults = new Dictionary<WebRequest, IAsyncResult>();
        for (int i = 0; i < CallCount; i++)
        {
            var request = WebRequest.Create(new Uri(LongMethodUri));
            asyncResults[request] = request.BeginGetResponse(null, null);
        }
        foreach (var pair in asyncResults)
        {
            pair.Key.EndGetResponse(pair.Value);
        }
    }

    static void TaskFromAsyncTest()
    {
        var tasks = Enumerable.Range(0, CallCount).Select(i =>
        {
            var request = WebRequest.Create(new Uri(LongMethodUri));
            return Task.Factory.FromAsync
                (
                    request.BeginGetResponse,
                    (Func<IAsyncResult, WebResponse>)request.EndGetResponse,
                    null
                );

        });

        Task.WaitAll(tasks.ToArray());
    }

    static void SynchronousTaskTest()
    {
        var tasks = Enumerable.Range(0, CallCount).Select(i => Task.Run(() =>
        {
            using ((WebRequest.Create(new Uri(LongMethodUri))).GetResponse()) { }
        }));

        Task.WaitAll(tasks.ToArray());
    }
}



Важно не забыть убрать ограничение на число параллельных коннектов к одному и тому же адресу в app.config:
  <system.net>
    <connectionManagement>
      <remove address="*"/>
      <add address="*" maxconnection="999999"/>
    </connectionManagement>
  </system.net>



Имеем закономерный результат:
BeginEndTest took 2346 ms
TaskFromAsyncTest took 2245 ms
SynchronousTaskTest took 11067 ms
Worker threads: 3, IO threads: 3
Any key press you...



Однако! При определенных условиях синхронный вызов метода сервиса в таске может оказаться выгоднее по скорости. Например, если этот метод — очень быстрый.
Поднимем сервис на локальной машине, уберем из его метода Thread.Sleep() и снимем лимит на число потоков. Имеем:
BeginEndTest took 471 ms
TaskFromAsyncTest took 626 ms
SynchronousTaskTest took 202 ms
Worker threads: 32767, IO threads: 1000
Any key press you...



Таким образом, выяснять, какой из вариантов быстрее и эффективнее в Вашем конкретном случае, все равно придется с помощью нагрузочных тестов.

P.S. — речь здесь идет об огромном числе параллельных вызовов в нагруженных системах. Если у Вас виндовый клиент, дергающий что-то раз в час — все, что выше, можно не читать.
Re[10]: BeginAsync vs Tasks
От: Tom Россия http://www.RSDN.ru
Дата: 16.02.14 14:29
Оценка:
Здравствуйте, Tom, Вы писали:

А>>Тоже легко проверить что это утверждение неверно, новые потоки появляются сразу после вызова BeginGetResponse

Tom>Вы не правильно проверяете.
Tom>То что поток создался в пуле это вполне нормально.
Tom>Главное что ы во время того как работает BeginGetResponse поток в пуле не использовался.
Почитал я документацию на BeginGetResponse — это полный взрыв мозга.
Часть функции работает синхронно.... Т.е. выигрыша по сути от её асинхронности нет вообще.
Народная мудрось
всем все никому ничего(с).
Re[2]: BeginAsync vs Tasks
От: Аноним  
Дата: 16.02.14 15:04
Оценка:
_>Имеем закономерный результат:
_>
_>BeginEndTest took 2346 ms
_>TaskFromAsyncTest took 2245 ms
_>SynchronousTaskTest took 11067 ms
_>Worker threads: 3, IO threads: 3
_>Any key press you...
_>



_>Однако! При определенных условиях синхронный вызов метода сервиса в таске может оказаться выгоднее по скорости. Например, если этот метод — очень быстрый.

_>Поднимем сервис на локальной машине, уберем из его метода Thread.Sleep() и снимем лимит на число потоков. Имеем:
_>
_>BeginEndTest took 471 ms
_>TaskFromAsyncTest took 626 ms
_>SynchronousTaskTest took 202 ms
_>Worker threads: 32767, IO threads: 1000
_>Any key press you...
_>



Мне кажется тест не совсем корректный
т.к. в случае 3. синхронный метод скачивает все данные, в асинхронных вариантах первый callback ни о чем не говорит, там может быть принят только 1 байт.
Обычно в обработчиках запускается повторно BeginReceive пока не будут получены все данные, вот этого в тестах нет, поэтому вероятно тест с удаленным сервером дал такой более быстрый результат.
Re[3]: BeginAsync vs Tasks
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 16.02.14 16:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Мне кажется тест не совсем корректный

А>т.к. в случае 3. синхронный метод скачивает все данные, в асинхронных вариантах первый callback ни о чем не говорит, там может быть принят только 1 байт.
А>Обычно в обработчиках запускается повторно BeginReceive пока не будут получены все данные, вот этого в тестах нет, поэтому вероятно тест с удаленным сервером дал такой более быстрый результат.

Код вызываемого метода:

// GET api/values
public IEnumerable<string> Get()
{
   Thread.Sleep(1000);
   return new string[] { "value1", "value2" };
}


Метод даже 1 байт выдает не сразу, а через секунду.

Впрочем, вставьте вычитывание всего респонса сами и проверьте.
Re[4]: BeginAsync vs Tasks
От: Аноним  
Дата: 16.02.14 18:31
Оценка:
Здравствуйте, scale_tone, Вы писали:

_>Здравствуйте, Аноним, Вы писали:


А>>Мне кажется тест не совсем корректный

А>>т.к. в случае 3. синхронный метод скачивает все данные, в асинхронных вариантах первый callback ни о чем не говорит, там может быть принят только 1 байт.
А>>Обычно в обработчиках запускается повторно BeginReceive пока не будут получены все данные, вот этого в тестах нет, поэтому вероятно тест с удаленным сервером дал такой более быстрый результат.

_>Код вызываемого метода:


_>
_>// GET api/values
_>public IEnumerable<string> Get()
_>{
_>   Thread.Sleep(1000);
_>   return new string[] { "value1", "value2" };
_>}
_>


_>Метод даже 1 байт выдает не сразу, а через секунду.


_>Впрочем, вставьте вычитывание всего респонса сами и проверьте.


Ну так это ваш локальный, на нем собственно разницы и не видно, точнее синхронный даже в плюсе.
А на удаленном сервере такой же код ?
Re[5]: BeginAsync vs Tasks
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 16.02.14 19:29
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Ну так это ваш локальный, на нем собственно разницы и не видно, точнее синхронный даже в плюсе.

А>А на удаленном сервере такой же код ?

Еще раз.

По адресу http://beginendtasktest.azurewebsites.net/api/values сейчас доступен метод, код которого следующий:
// GET api/values
public IEnumerable<string> Get()
{
   Thread.Sleep(1000);
   return new string[] { "value1", "value2" };
}


Этот код задеплоил туда я. Специально чтобы смоделировать долгий сетевой вызов.
То, что метод выполняется секунду, хорошо видно:


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

Множество параллельных синхронных вызовов другого, более быстрого метода в теле таски иногда может работать быстрее, чем такое же множество параллельных асинхронных вызовов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.