В чем преимущество запуска асинхронного кода с помощью task.run()

Мне трудно понять преимущества переноса асинхронной работы на Task.Run(). Раньше было много вопросов об асинхронной работе, выгружаемой в задачу, но я никогда не видел, чтобы решалась самая большая загадка для меня.

рассмотреть два варианта:

  • Опция 1:
var t1= Task.Run( async() =>
        {
            await CPUBoundWorkAsync();
        });
  • вариант 2:
var t2= Task.Run( () =>
        {
             CPUBoundWork();
        });

При втором варианте работа выгружается в отдельный поток, таким образом «достигается» асинхронность, и основной поток может вернуться к тому, для чего он нужен. При первом варианте используется асинхронный метод, а делегат выражается как асинхронный. Оба варианта должны давать неотличимый результат с точки зрения отсутствия блокировки основного потока и одновременного завершения работы, связанной с процессором. Есть ли польза от использования асинхронного метода в Task.Run? мне кажется, что это по сути, позволяя работе, которая уже выполняется асинхронно (в другом неблокирующем потоке), также выполняться асинхронно.. Может ли пул потоков или что-то еще, управляющее этими потоками задач, прочитать это? а затем, возможно, дать этому ожидающему потоку какую-то другую работу? если это так, я не видел упоминания об этом ни в одном блоге эксперта или на соответствующей странице в Интернете.

Являются ли f1 и f2 неизменными между двумя вариантами? Это означает, что в первом варианте вы ожидаете f1до, вызывая f2, тогда как во втором варианте вы вызываете f1, игнорируете возвращаемый объект Task, не (a) ждете его завершения, а затем немедленно вызываете f2, возможно, пока f1 все еще выполняется ?

Lasse V. Karlsen 16.05.2022 21:22

@LasseV.Karlsen, вы правы, отредактировал вопрос.

Ben Guri 16.05.2022 21:34

Ваш вопрос связан с этим? ожидание Task.Run против ожидания

Theodor Zoulias 16.05.2022 21:37

@TheodorZoulias, этот вопрос касается чего-то другого и гораздо более простого

Ben Guri 16.05.2022 21:43

Отвечает ли это на ваш вопрос? ожидание Task.Run против ожидания

MKR 16.05.2022 23:12

@MKR отвечает на другой вопрос

Ben Guri 16.05.2022 23:17

Честно говоря, я не понимаю вопроса. Вы представляете два варианта, которые имеют значение только в меньшинстве случаев, когда синхронный и асинхронный API доступны для одной и той же функциональности (Read/AsyncRead в вашем примере). Но вы не спрашиваете, какой из них лучше, потому что я предполагаю, что вы это уже знаете. Таким образом, вы на самом деле сравниваете не вариант 1 с вариантом 2, а вариант 1 с вариантом 3, не говоря, что такое вариант 3, и подразумевая, что это не естественно var t3 = AsyncRead();. Хотите уточнить?

Theodor Zoulias 16.05.2022 23:39

@TheodorZoulias Стивен Клири понял и отлично ответил на свой ответ ниже. Он указал, что метод возвращается в пул потоков после «ожидания», поэтому поток возвращается и может выполнять другую работу, что является «выгодой» от этого в контексте Task.Run().

Ben Guri 17.05.2022 18:09

@ Бен Стивен Клири, возможно, лучше умеет читать мысли, чем остальные, и понял, что вы действительно хотели знать, из той небольшой информации, которую вы дали в вопросе. Итак, если вы намеревались получить ответ от Стивена, цель достигнута! :-)

Theodor Zoulias 17.05.2022 18:34

@TheodorZoulias, или, возможно, вы мало склонны интерпретировать вопросы таким образом, чтобы это соответствовало вашей зоне комфорта знаний;)

Ben Guri 17.05.2022 18:42

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

Theodor Zoulias 17.05.2022 18:54

@TheodorZoulias Я думаю, что это довольно ясно, и я снова пересмотрел его, чтобы сделать его еще яснее, очевидно, ответ, предоставленный Стивеном, дал на него точный и короткий ответ. вопрос затрагивает важную, но нюансированную деталь, и что простой ответ на него отсутствует во многих источниках, которые я проверил, включая сообщения в блогах экспертов и онлайн-курсы обучения. Я чувствую, что этот вопрос может помочь еще нескольким разработчикам, которые могут наткнуться на асинхронность в контексте Task.Run и быть пронизанными таким же образом.

Ben Guri 17.05.2022 19:06

Мне до сих пор непонятно, потому что я не знаю, что вы хотите с чем сравнить. Если вопрос "зачем мне использовать X, если нет другого выхода", то очевидный ответ — «вы вынуждены использовать Х, потому что другого выхода нет». Пожалуйста, рассмотрите возможность представления осмысленных вариантов, чтобы вопрос был осмысленным.

Theodor Zoulias 17.05.2022 19:13

Кстати, если вы думаете, что, изменив имена методов в вопросе с AsyncRead/Read на CPUBoundWorkAsync/CPUBoundWork, вопрос станет более ясным, по крайней мере, для меня это не так. Название CPUBoundWorkAsync специально создает для меня противоречивые ожидания относительно того, что этот метод может делать внутри. CPUBound-часть означает, что он интенсивно использует по крайней мере один поток, а Async-часть — что он использует нет нити. Мне интересно, что другие люди думают об этом.

Theodor Zoulias 17.05.2022 19:13

@TheodorZoulias, очевидно, я сделал больше, чем просто изменил имена, но делайте, как хотите.

Ben Guri 17.05.2022 19:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
15
98
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

В вашем примере, если f1() и f2() являются асинхронными (в том смысле, что они возвращают задачу), тогда ключевое слово async позволит вам ожидать тех, кто внутри вашего Task.Run().

Ваш вопрос похож на «почему вы помечаете метод Любые как асинхронный»… потому что вы хотите запускать асинхронный код внутри. Или, точнее, вы хотите, чтобы компилятор построил конечный автомат для обработки «ожидания» завершения асинхронной операции.

Я отредактировал вопрос, очевидно, я не имел в виду, что f1() и f2() возвращаются немедленно

Ben Guri 16.05.2022 21:44

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

Scott Perham 16.05.2022 21:50

Я не уверен, правильно ли я понял ваш вопрос. Ориентируясь на «по сути, это позволяет коду, который уже выполняется асинхронно, также выполняться асинхронно»:

Хотя запуск асинхронного кода внутри Task.Run кажется бессмысленным, бывают ситуации, когда это может быть необходимо. Асинхронные методы всегда выполняются синхронно, пока не произойдет первый «настоящий» асинхронный вызов. Хорошим примером является использование фоновые услуги.

Ответ принят как подходящий

With the 2nd option, the work is already being offloaded to a separate thread, then the asynchronicity is already gained in the scope of the program that invoked t2.

Task.Run не делает что-то асинхронным. Это позволяет вам запускать синхронный код в потоке пула потоков (и, таким образом, блокировать поток пула потоков вместо какого-либо другого потока), но я бы не сказал, что это «делает его асинхронным». Код по-прежнему синхронно блокирует поток.

Now although the work that is being done in the 1st option is declared and implemented as async, it's essentially letting code that is already being ran asynchronously, to also run itself asynchronously. What benefits from it ? Can the the scheduler or whatever manages those task threads read into this? and then perhaps give that awaiting thread some work on another task ?

Тредов нет await. Способы await. Когда поток запускает метод и попадает в await, этот метод приостанавливается, метод возвращается к вызывающей стороне, а поток продолжает выполнение. В случае делегата, переданного Task.Run, await вызовет возврат метода -- в пул потоков, тем самым возвращая поток в пул потоков. Когда задача awaited завершится, поток из пула потоков будет использоваться для возобновления выполнения метода; это может быть тот же поток или совершенно другой поток.

Дополнительная информация о как именно await работает находится в моем блоге.

if this is the case I haven't seen it mentioned in any expert blog post, or relevant page on the internet.

У меня серия на Task.Run этикет. По сути, Task.Run в основном используется для разгрузки синхронной или связанной с процессором работы из потока пользовательского интерфейса в приложениях с графическим интерфейсом. Это также иногда полезно в сценариях на стороне сервера, если вы хотите быстро начать что-то обрабатывать, вернуться назад и взять следующее для обработки. Есть еще несколько вариантов использования, но они редки.

Все эти причины могут относиться к асинхронным API. Иногда API появляться асинхронны, но на самом деле это не так. Или некоторые методы являются асинхронными, но они выполняют нетривиальный объем синхронной работы первый, поэтому в некоторых случаях Task.Run по-прежнему желателен даже с асинхронным кодом.

Привет спасибо. Подробная информация о потоке, возвращающемся в пул потоков, отвечает на вопрос. У меня было ощущение, что это должно быть поведение, но нигде не было указано явно, что я смотрел, возможно, это слишком много нюансов или очевидно для большинства программистов (?)

Ben Guri 17.05.2022 18:05

Другие вопросы по теме