Запустить и забыть несколько методов в C # - PullRequest
1 голос
/ 29 октября 2019

У меня есть функция Azure, которая может вызывать несколько конечных точек API, не ожидая результатов ни от одной из них.

Функция Azure запускается по триггеру таймера и запускается каждые 10 секунд.

Все мои вызовы API и параметры для их вызова хранятся в таблице SQL. Я хочу убедиться, что вызовы API выполняются, не дожидаясь завершения определенного вызова.

Это всего лишь план того, что я буду делать.

[FunctionName("FunctionScheduler")]
public static async Task RunAsync([TimerTrigger("*/10 * * * * *")]TimerInfo myTimer, ILogger log)
{
    log.LogInformation("FUNCTION SCHEDULER STARTING ..");

    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

    for(int i=0; i < 20; i++)
    {
        var task = Task.Run(() => ApiRef1(i, log));
        var taskref = await task;
    }

}

В настоящее время ApiRef1 () просто выводит значение переменной i. Я получаю ожидаемый результат печати чисел от 0 до 19. Я хочу параллельное выполнение метода ApiRef1 (), который в конечном итоге будет заменен методом, который выглядит следующим образом.

private static void CallApi(string apiName, string apiEndpoint, string methodType, string authenticationType, IDictionary<int, string> parameters, ILogger log)
{
    try
    {
        log.LogInformation($"Call to API {apiName} started.." );

        // Call API
    }
    catch (Exception ex)
    {
        log.LogInformation($"Exception {ex.Message} occurred.." );
    }
}

Есть ли лучший способсделать это или этот метод будет работать?

Ответы [ 3 ]

2 голосов
/ 29 октября 2019

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

Однако нас не волнуетрезультат задачи, поэтому нам не нужно ждать каждого задания в отдельности.

System.Collections.Generic.List<System.Threading.Tasks.Task> tasks = new System.Collections.Generic.List<System.Threading.Tasks.Task>();
for (int i = 0; i < 20; i++)
{
  tasks.Add(System.Threading.Tasks.Task.Run(() => ApiRef1(i, log));
}
await System.Threading.Tasks.Task.WhenAll(tasks);

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

1 голос
/ 29 октября 2019

Вы можете использовать функциональность асинхронных / задач. Вот один пример

    public static class AzureFunction
    {
        [FunctionName("SomeAzureFunction")]
        public static void Run([TimerTrigger("*/10 * * * * *")]TimerInfo myTimer, ILogger log)
        {
            Function1(log);
            Function2(log);
            Function3(log);
        }

        private static async void Function1(ILogger log)
        {
            await Task.Run(() =>
            {
                Thread.Sleep(6000);
                log.LogInformation("Function 1 now executed");
            });
        }

        private static async void Function2(ILogger log)
        {
            await Task.Run(() =>
            {
                Thread.Sleep(2000);
                log.LogInformation("Function 2 now executed");
            });
        }

        private static async void Function3(ILogger log)
        {
            await Task.Run(() =>
            {
                log.LogInformation("Function 3 now executed");
            });
        }
    }

(строки Threat.Sleep () предназначены только для того, чтобы показать вам, как / как функции выполняются независимо друг от друга)

В окне вывода выувидит, что все три функции запущены, но сначала будет завершена функция 3 (поскольку мы не спим потоком), затем завершится функция 2 (так как у нас 2-секундная задержка) и, наконец, функция 1 завершится (6-секундная задержка). ).

Обратите внимание, что все функции в этом примере имеют тип возврата «Void». Так что этот пример будет работать, только если вас не волнует какое-либо возвращаемое значение из функций.

Но я думаю, что это близко к тому, что вы просили

1 голос
/ 29 октября 2019

Task.Run() возвращает Task. Когда вы «стреляете и забываете», вам нет дела до этой задачи.

Чтобы взять то, что предложено DetectivePikachu , используйте сброс, чтобы гарантировать, что вас не волнует результат.

public void Run()
{
    ...

    _ = Task.Run(() => ApiRef1(i, log));

    ...
}

Метод, содержащий вызов Task.Run, НЕ сам асинхронен. Если у вас нет других вызовов методов, использующих await, вам больше не требуется асинхронизация.

...