在同步调用方法中调用异步等待方法

Call async await method in sync calling method

这只是关于我在 window 服务中所做的事情的想法。 我从这个 video 得到了并行处理的想法。

我有两种不同的方法和一个模型class。

型号Class代码:

public class Email(){
    public string Recipient { get; set; }
    public string Message { get; set; }
}

方法是这样的:

public void LoadData(){
    while(Main.IsProcessRunning){
        // 1. Get All Emails
        var emails = new dummyRepositories().GetAllEmails(); //This will return List<Emails>.
        // 2. Send it
        // After sending assume that the data will move to other table so it will not be query again for the next loop.
        SendDataParallel(emails);//this will function async? even though the calling method is sync.

        // This will continue here or wait until it already send?
        // If it will continue here even though it will not send already
        // So there's a chance to get the email again for the next loop and send it again?
    }
}

//This will send email at parallel
public async void SendDataParallel(IList<Email> emails){
    var allTasks = emails.Select(SendDataAsync);
    await TaskEx.WhenAll(allTasks);
}

//Assume this code will send email asynchronously. (this will not send email, for sample only)
public async void SendDataAsync(Email email){
    using (var client = new HttpClient())
    {
        client.PostAsync(email);
    }
}

我只想获取所有排队的电子邮件,然后并行发送,然后等到它已经发送。 我避免在收到的每封电子邮件中使用 foreach

您的编译器不会突出显示您的错误代码吗?

如果您将您的方法标记为异步而它没有 return 任何值,您应该将您的 return 类型设置为 Task,而不是 void:

public async Task SendDataParallel(IList<Email> emails){
    var allTasks = emails.Select(SendDataAsync);
    await Task.WhenAll(allTasks);
}

你的第二种方法也应该return一个任务,否则你想在第一种方法中等待什么?

public async Task SendDataAsync(Email email){
    using (var client = new HttpClient())
    {
        return client.PostAsync(email);
    }
}

现在您可以 Select SendDataParallel 中的所有 SendDataAsync 任务和 .Wait() 它是同步模式下 LoadData 中的任务:

public void LoadData(){
    while(Main.IsProcessRunning){
        var emails = new dummyRepositories().GetAllEmails(); //This will return List<Emails>.
        SendDataParallel(emails).Wait();
    }
}

更多信息,您可以在 MSDN 上的其他 SO 问题和文档中找到阅读答案:

当您使用基于 foreach 循环的 LINQ Select() 时,下一篇文章也可能有用: Nested task inside loop

让我们从底部开始:

  1. 您在实际完成异步接收 HttpResponseMessage 之前处置您的客户端。你需要让你的方法 async Taskawait 在里面:

    public async Task SendDataAsync(Email email)
    {
        using (var client = new HttpClient())
        {
            var response = await client.PostAsync(email);
        }
    }
    
  2. 目前,您的 SendDataParallel 无法编译。同样,它需要 return a Task:

    public Task SendEmailsAsync(IList<Email> emails)
    {
        var emailTasks = emails.Select(SendDataAsync);
        return Task.WhenAll(allTasks);
    }
    
  3. 在顶部,您需要 await on SendEmailsAsync:

    public async Task LoadDataAsync()
    {
        while (Main.IsProcessRunning)
        {
            var emails = new dummyRepositories().GetAllEmails(); 
            await SendEmailsAsync(emails);
        }
    }
    

编辑:

如果您 运行 在 windows 服务中,您可以将其卸载到 Task.Run 并使用 async 关键字:

var controller = new Controller();
_processThread = Task.Run(async () => await controller.LoadDataAsync());