Выполнение двух методов одного и того же класса и ожидание продолжения одного из них

Как я могу одновременно выполнить два метода, используя асинхронный режим, и дождаться, пока 1 метод finalize продолжит работу с другим?

public class Foo{
    public async Task<string> Method1()
    {
        //run a task
        return result;
    }

    public async void Method2(string result)
    {
        //do some work
        //do some work
        //do some work
        //wait for method1
        //do something with result
    }
}

Foo foo = new Foo();
var result = await foo.Method1();
foo.Method2(result);

Примечание: async void обычно считается очень плохой идеей.

DavidG 10.04.2019 02:49

Ваш вопрос на самом деле противоречив. Вы говорите, что хотите выполнить два метода "сразу" (параллелизм), но затем вы говорите, что хотите дождаться завершения первого (сериализованного). Кроме того, зачем использовать async/await?

MickyD 10.04.2019 03:02

@MickyD Противоречиво? Это довольно простой способ одновременного выполнения работы: «Я буду выполнять эту работу, пока вы выполняете эту работу, и я дам вам знать, как только мне понадобятся ваши результаты» (фактически, код в ответе Теодора Зулиаса — это то, что предлагается в MIcrosoft Документы для смешивания параллелизма с асинхронностью) TPL здесь не требуется, это правильно, но что, если Method1 выполняет асинхронную работу?

Camilo Terevinto 10.04.2019 03:12

@CamiloTerevinto Возможно. Я бы сказал, что это полупараллелизм с добавленным логическим продолжением

MickyD 10.04.2019 03:34
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
76
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Следуя вашему примеру, где Method1 и Method2 вызываются отдельно (Method2 не знает о Method1), вы получите желаемое поведение, передав Task Method1 методу Method2.

public class Service
{
    public async Task<string> MethodOne()
    {
        // do something
        var result = await CalculateSomeResult();
        return result;
    }

    public async Task MethodTwo(Task<string> task)
    {
        // do some work
        // do some work

        var methodOneResult = await task;
        // do something with the result of methodOne
    }
}

Применение

var service = new Service();

var methodOneTask = service.methodOne();
await service.MethodTwo(methodOneTask);

На самом деле это еще один хороший подход (с небольшой проблемой, что код не компилируется из-за async void, как указал @CamiloTerevinto). Это немного более гибко, чем объединение вызова Method1 непосредственно в Method2, как это предлагается в принятом ответе.

Alexei Levenkov 10.04.2019 03:49

@CamiloTerevinto, это была слепая копия вопроса ОП, я предполагал, что асинхронные методы никогда не имеют подписи void.

Fabio 10.04.2019 04:10

Если я вас правильно понял, вам нужен Method2 для использования результатов, возвращаемых Method1 - при этом вам нужно вызывать Method2 изнутри Method1, а не после него:

public class Foo{
    public async Task<string> Method1()
    {
        //run a task
        return result;
    }

    public async void Method2(string result)
    {
        //do some work
        //do some work
        //do some work
        var intermediaryResult = await Method1();
        //do something with result
    }
}

Foo foo = new Foo();

await foo.Method2(result);

(Кроме того, вам также нужно ждать Method2 - они оба асинхронны)

Кстати, вы должны никогда не используйте асинхронные методы void, если у вас нет выбора - поэтому вместо этого Method2 должен возвращать Task.

Этот код не имеет смысла. Почему объявлен Method2 Method2(string result)? Почему вы использовали await foo.Method2(result);, если Method2 — это async void?

Camilo Terevinto 10.04.2019 03:16

@CamiloTerevinto Я до сих пор не уверен, чего пытается достичь OP, поэтому я бы предпочел дождаться разъяснений, а не пытаться угадать, что исправить :)

Darth Veyda 10.04.2019 03:18

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

Camilo Terevinto 10.04.2019 03:20
Ответ принят как подходящий

Как насчет этого?

public async Task<string> Method2()
{
    //do some work
    //do some work
    //do some work
    var result = await foo.Method1();
    //do something with result
    return result;
}

Foo foo = new Foo();
var result = await foo.Method2();

Для (полу)параллельного выполнения:

public async Task<string> Method2()
{
    var task1 = foo.Method1();
    //do some work
    //do some work
    //do some work
    var result = await task1;
    //do something with result
    return result;
}

Постановка проблемы @Camilo OP предполагает, что желательно последовательное выполнение, тем более что OP, похоже, хочет, чтобы результат метода 1 использовался в методе 2.

Llama 10.04.2019 02:53

@ Камило Теревинто, ты прав. Я обновил свой ответ.

Theodor Zoulias 10.04.2019 02:58

@Джон Это совсем не то, что я понимаю из //wait for method1, но давайте позволим ОП решить

Camilo Terevinto 10.04.2019 03:08
public class Foo
{
public async Task<string> Method1()
{
    //run a task
    return result;
}

public async void Method2(string result)
{
    //do some work
    //do some work
    //do some work
    //wait for method1
    //do something with result
}
}
await Task.Run(()=>
{
Foo foo = new Foo();
var result = foo.Method1();
foo.Method2(result);
});

Вы можете использовать EventWaitHandle:

public class Sequence {
        EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.ManualReset);
        public async Task Tsk1() {

            Console.WriteLine("Did some work from tsk1");
            handle.Set();

        }
        public async Task Tsk2() {
            handle.WaitOne();
            Console.WriteLine("Doing work after tsk1 finished");
            //do some other stuff
        }
    }
    class Program {
        static async Task Main(string[] args) {

                Sequence seq = new Sequence();
                var t2 =Task.Run(seq.Tsk2);
                var t1 =Task.Run(seq.Tsk1);

                await Task.WhenAll(t1, t2);
                Console.WriteLine("finished both");
        }
    }

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