Является ли синхронный метод void с аргументами Func<Task> или Func<Task<T>> практически полезным?

Я учу своих друзей ключевому слову async-await и до сих пор приводил им несколько примеров.

static async Task Do(Func<Task> job)
{
    // some algorithm depends on job parameter.
    await job();
} 

Я думаю, что этот пример практически полезен во многих сценариях.

Вопрос

Есть ли польза от методов void с аргументами типа Func<Task> или Func<Task<T>>? Насколько я думаю, существование такого метода имеет смысл, потому что блокировать асинхронные методы не рекомендуется. Всегда рады любым комментариям!

static Task Do(Func<Task> job) { return job(); }? return DoSomethingElse(job)?
canton7 29.05.2019 11:37

"Следующее не кажется полезным ИМХО." - это примерно так же полезно, как await job()... Предполагается, что другая работа выполняется до/после вызова job(), независимо от того, ожидается ли Task, возвращаемое job(), или нет.

canton7 29.05.2019 11:38

Второй выполняет функцию job и возвращает результат. Ничего больше/меньше

Jeroen van Langen 29.05.2019 11:41

Я написал методы, которые принимают Func<Task> job и запускают задание в другом потоке. Метод может возвращать или не возвращать собственный Task, но не будет async.

canton7 29.05.2019 11:41

Ваш метод возврата void может быть не синхронным. Это может сделать что-то вроде отправки job в другую ветку.

canton7 29.05.2019 11:55

@ArtificialOdorlessArmpit Нет, я никогда не говорил, что ты будешь использовать job().Wait()

canton7 29.05.2019 12:24

Task может в конечном итоге использоваться с ContinueWith, или он может ожидаться в методе async void, или, возможно, он полностью игнорируется (как часто бывает Task, возвращаемый из Task.Run), или, может быть, он помещается в очередь, а поток-потребитель позже ожидает его. .

canton7 29.05.2019 12:40

@canton7: ​​Извините, я не могу понять, что вы только что объяснили, без кода. Не могли бы вы опубликовать простейший код в качестве ответа?

user271232 29.05.2019 12:46
Стоит ли изучать 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
8
288
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Да, использование неасинхронных методов, выполняющих делегаты, может быть полезным, например, запросы LINQ, предоставляемые .Net.

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

Возьмем, к примеру, метод Список.ForEach(Действие).

(ПРИМЕЧАНИЕ: это НЕТ, фактическая реализация будет в .Net!)

public void ForEach(Action<T> action) {
    if (action is default(Action<T>))
        throw new ArgumentNullException(nameof(action), "Action must not be null!");

    foreach (var element in this) {
        // Execute provided action (delegate)
        action(T);

    }
}

В этом случае вы хотите, чтобы цикл выполнялся синхронно, например, из-за безопасности потоков.


Другим примером может быть метод public static System.Collections.Generic.IEnumerable<TSource> Where<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate);, который также будет работать синхронно из соображений безопасности потоков, поэтому ваши результаты возвращаются, как и ожидалось.

Вы также можете всегда вызывать методы из отдельного потока (или асинхронного метода), если это необходимо. Большинство консольных приложений работают синхронно, так как нет графического интерфейса, который должен реагировать.


РЕДАКТИРОВАТЬ

Другим примером синхронных методов с Func в качестве параметра может быть консольное приложение. Допустим, вы реализуете консольное приложение с зависимостью от библиотеки (которую вы не можете контролировать). Эта библиотека предоставляет только задачи. В консольном приложении вы обычно не используете/не нуждаетесь в асинхронных приложениях, поскольку нет графического интерфейса, который может блокироваться, и/или ваше приложение должно продолжать работу только после того, как пользователь введет ввод.

// External method returning a Task
public Task<int> DoFooAsync(object myParam);

public bool ParseMyFoo(Func<Task<int>> myTask) {
    var result = myTask().Result;

    if (result == 0xbadbeef || result == 0xf00dbabe) {
        Console.WriteLine("Schrödingers takeaway");
    }
}

public static void Main(string[] args) {
    Console.WriteLine("Assesment: {0}", ParseMyFoo(DooFooAsync(Console.ReadLine()));
}

Почему вы взяли пример с Action, а не Func<Task> или Func<Task<T>>?

user271232 29.05.2019 12:15

Они по сути одинаковы, это был просто пример реализации. Я добавил второй пример, используя Func<T> внизу. Я добавлю еще код.

SimonC 29.05.2019 13:15

@canton7 Извините, вы правы. Забыл свойство Result.

SimonC 29.05.2019 13:55
Main не сможет поймать какие-либо возможные исключения, выброшенные ParseMyFoo, поэтому этот пример слишком плох для учебных целей.
user271232 29.05.2019 14:05
Ответ принят как подходящий

Is there any usefulness of having void methods with arguments of type Func<Task> or Func<Task<T>>?

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

Одним из примеров, который приходит на ум, является своего рода метод Add для выполнения очереди асинхронной работы. Делегат будет выполняться в другом месте, в коде "обработчика очереди". Добавление делегата в очередь будет синхронной операцией, даже если сам делегат является асинхронным. Вот пример.

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