简体   繁体   English

C# 中的 Fire and Forget 多种方法

[英]Fire and Forget multiple methods in C#

I have an Azure function which would have the ability to call multiple API endpoints without waiting for the results from any of them.我有一个 Azure function 能够调用多个 API 端点,而无需等待其中任何一个端点的结果。

The Azure function runs on a timer trigger and runs every 10 seconds. Azure function 在定时器触发器上运行,每 10 秒运行一次。

All my API calls and parameters to call them are stored in a SQL table.我所有的 API 调用和调用它们的参数都存储在 SQL 表中。 I want to make sure that the API calls are made without waiting for a particular call to be finished.我想确保在不等待特定调用完成的情况下进行 API 调用。

This is just a blueprint of what I'll be doing.这只是我将要做的事情的蓝图。

[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;
    }

} }

Currently ApiRef1() simply prints out the value of the variable i.目前 ApiRef1() 只是打印出变量 i 的值。 I get the expected output of printing numbers 0 to 19. I want parallel executions of the ApiRef1() method which will eventually be replace by a method that looks like this.我得到了预期的 output 打印数字 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.." );
    }
}

Is there a better way to do this or will this method work?有没有更好的方法来做到这一点,或者这种方法会奏效吗?

As you're using an Azure function you cannot have true fire and forget as you risk the function terminating before the completion of all the task(s).当您使用 Azure function 时,您不能真正着火而忘记,因为您冒着 function 在完成所有任务之前终止的风险()。

However, we don't care for the result of the task, so we need not await each task individually.但是,我们不关心任务的结果,所以我们不需要单独等待每个任务。

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);

This allows all the tasks to fire in parallel, but pause further execution until they're all complete, ensuring the completion of the tasks before the process is terminated.这允许所有任务并行触发,但暂停进一步执行直到它们全部完成,确保在进程终止之前完成任务。

Task.Run() returns a Task . Task.Run()返回一个Task When you "fire and forget", you don't care about that task.当您“解雇并忘记”时,您就不会关心该任务。

To take what DetectivePikachu suggested, use a discard to ensure that you don't care about the result.要接受DetectivePikachu的建议,请使用丢弃以确保您不关心结果。

public void Run()
{
    ...

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

    ...
}

The method containing the Task.Run call is NOT async itself.包含Task.Run调用的方法本身不是异步的。 Unless you have other method calls using await , you don't need async anymore.除非您使用await进行其他方法调用,否则您不再需要异步。

You can make use of the async/Task functionality.您可以使用 async/Task 功能。 Here is one example这是一个例子

    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");
            });
        }
    }

(the Threat.Sleep() lines are only there to show you how/that the functions are executed independent from each other) (Threat.Sleep() 行仅用于向您展示函数如何/如何相互独立地执行)

In the output window you will see that all three functions are started, but Function 3 will finish first (as we do not sleep the thread), then function 2 will finish (as we have a 2 second delay) and at last function 1 will finish (6 seconds delay). In the output window you will see that all three functions are started, but Function 3 will finish first (as we do not sleep the thread), then function 2 will finish (as we have a 2 second delay) and at last function 1 will完成(延迟 6 秒)。

Please notice that all functions in this example have a return type "Void".请注意,此示例中的所有函数都有一个返回类型“Void”。 So this example will only work if you do not care about any return value from the functions.因此,此示例仅在您不关心函数的任何返回值时才有效。

But I think this comes close to what you asked for但我认为这接近你要求的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM