【问题标题】:Call async await method in sync calling method在同步调用方法中调用异步等待方法
【发布时间】:2015-11-09 20:57:04
【问题描述】:

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

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

模型类代码:

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

【问题讨论】:

  • 问题或问题是什么?
  • @SriramSakthivel 已编辑。,.
  • @janmvtrinidad 这里还是没有问题。
  • @AntP 我把问题作为代码注释。,.

标签: c# asynchronous async-await c#-5.0


【解决方案1】:

让我们从底部开始:

  1. 您在真正完成异步接收HttpResponseMessage 之前处置您的客户端。您需要将方法 async Taskawait 放在里面:

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

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

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

【讨论】:

  • LoadDataAsync加静态类型就行了,?
  • 你希望方法是static
  • 我将在windows服务中使用LoadData作为后台服务调用。,.
  • @janmvtrinidad 好的,但这与static 方法有什么关系?
  • 我会创建一个像_processThread = new Thread(Controllers.LoadData) { IsBackground = true };这样的线程,它需要是静态的才能将LoadData作为线程的参数。
【解决方案2】:

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

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

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

您的第二种方法也应该返回一个任务,否则您想(a)在第一种方法中等待什么?

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

现在您可以在 SendDataParallel 和 .Wait() 中选择所有 SendDataAsync 任务,它是 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

【讨论】:

  • 我将在我的 LoadData() 上使用 wait()..,我认为 SendDataAsync 会出错,返回时没有 await 关键字..,无论如何感谢您的解决方案。, .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
相关资源
最近更新 更多