当前位置: 首页 > 知识库问答 >
问题:

在foreach循环(c#)内调用异步函数

卓学智
2023-03-14

我在一个循环中调用了一个异步函数来发送电子邮件,但是有一段时间控件没有返回,也没有发送电子邮件,但是主UI线程完成了。

                 var sendEmailtasks = new List<Task>();
                 foreach   (var email in emailList)
                {
                    var emailResTask =   Task.Run(async() => await 
                    emailingService.SendEmail(email));
                    sendEmailtasks.Add(emailResTask);                    
                }
               await Task.WhenAll(sendEmailtasks);

当我把等待任务。WhenAll(发送电子邮件任务);循环内的线工作正常,但当我把这条线放在循环外时,它不工作,但实际上它应该在循环外。我在sendEmail方法中有很多异步方法,所以我认为有些线程彼此重叠。任何线索。

共有1个答案

狄承望
2023-03-14

如果不知道内部发生了什么,我们无法确定发生了什么。但是,这一行:

var emailResTask = Task.Run(async() => await emailingService.SendEmail(email));

看起来很可疑。如果SendEmail()函数返回任务,则可以简化代码:

Console.WriteLine("Creating tasks");
foreach (var email in emailList)
{
    var emailResTask = emailingService.SendEmail(email);
    sendEmailtasks.Add(emailResTask);
}
Console.WriteLine("Finished creating tasks");
await Task.WhenAll(sendEmailtasks);

但是,如果您的SendEmail()函数不是异步的,它可能仍然会阻塞,并且您不会看到您的任务并行运行;例如,此方法:

public Task SendEmail(string email)
{
    Console.WriteLine($"Sending email to {email}");
    Task.Delay(3000).Wait();
    Console.WriteLine($"Done ({email}).");
    return Task.CompletedTask;
}

将首先执行,然后返回:

Creating tasks
Sending email to one
Done (one).
Sending email to two
Done (two).
Finished creating tasks

但是,此函数不会阻塞(通过使用异步延迟方法):

public async Task SendEmail(string email)
{
    Console.WriteLine($"Sending email to {email}");
    await Task.Delay(3000);
    Console.WriteLine($"Done ({email}).");
    return Task.CompletedTask;
}

这一块也不会:

public Task SendEmail(string email)
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine($"Sending email to {email}");
        Thread.Sleep(3000);
        Console.WriteLine($"Done ({email}).");
    });
}

以上两个示例都在我的计算机上输出以下内容:

Creating tasks
Sending email to one
Sending email to two
Finished creating tasks
Done (one).
Done (two).

如果您的sendmail()被阻止,那么在新的任务中包装(如上面的最后一个示例)可能会有所帮助。

 类似资料:
  • 问题内容: 我如何访问传递给fs.lstat函数的变量? 问题答案: 这是使用而不是for循环迭代值的完美理由。 另外,您可以使用@Aadit建议的闭包:

  • 问题内容: 我在NodeJS中有一个forEach循环,遍历一系列键,然后从Redis异步检索其值。循环和检索完成后,我想返回该数据集作为响应。 我目前的问题是因为数据检索是异步的,发送响应时没有填充我的数组。 如何在我的forEach循环中使用promise或回调,以确保响应与数据一起发送? 问题答案: 我在这里使用Bluebird Promise 。请注意,代码的意图非常清晰并且没有嵌套。 首

  • 问题内容: 在循环中使用/ 是否有任何问题?我试图遍历文件数组和每个文件的内容。 这段代码确实有效,但是这可能会出问题吗?我让某人告诉我,您不应该在这样的高阶函数中使用/ ,所以我只是想问一下这是否有问题。 问题答案: 确保代码确实有效,但是我很确定它不会实现您期望的功能。它只会触发多个异步调用,但此后函数会立即返回。 顺序阅读 如果要顺序读取文件, 则不能使用。只需使用现代循环即可,该循环将按预

  • 问题内容: 我正在像这样的双循环内进行一些计算: 有没有办法让Loop在执行功能之前先完成?或程序在继续执行… 之前知道循环是否完成的任何方式 我可能会错过一些论坛,但是我发现的那些论坛并没有帮助我实现我想要实现的目标,而且我在NodeJS中做到了这一点,同时我也在问是否有现有的图书馆可以实现这一目标。 我忘了加起来,还是应该再问一个问题? 有没有一种方法可以同步进行迭代,即仅在当前迭代完成后才继

  • 除了前面介绍的几种循环语句外,C# 同样也支持 foreach 循环,使用 foreach 可以遍历数组或者集合对象中的每一个元素,其语法格式如下: foreach(数据类型 变量名 in 数组或集合对象){     语句块; } foreach 会在每次循环的过程中,依次从数组或集合对象中取出一个新的元素放到 里定义的变量中,直到所有元素都成功取出后退出循环。 【示例】使用 foreach 循环

  • 本文向大家介绍C# Foreach循环,包括了C# Foreach循环的使用技巧和注意事项,需要的朋友参考一下 示例 foreach将迭代实现的类的任何对象IEnumerable(请注意IEnumerable<T>从其继承的对象)。此类对象包括一些内置对象,但不限于:List<T>,T[](任何类型的数组),Dictionary<TKey, TSource>以及诸如IQueryable和IColl