C# 让多个线程共享方法工作负载

C# 让多个线程共享方法工作负载,c#,C#,我有一个名为asyncStartList的方法,它发送一系列提供给它的电子邮件,我正试图找出如何在有大量电子邮件的情况下使用多个线程来加速处理过程: public async Task asyncStartList() { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); for (int i = 0; i < listLength; i++) { currentMai

我有一个名为
asyncStartList
的方法,它发送一系列提供给它的电子邮件,我正试图找出如何在有大量电子邮件的情况下使用多个线程来加速处理过程:

public async Task asyncStartList()
{
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();   

    for (int i = 0; i < listLength; i++)
    {
        currentMailAddress = emailingList[i];
        await Task.Run(() => MailingFunction());
        currentMailAddress = "";
        Console.WriteLine("Your mail to {0} was successfully sent!", emailingList[i]);
    }

    stopWatch.Stop();
    TimeSpan ts = stopWatch.Elapsed;

    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
        ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

    Console.WriteLine("Time for completion " + elapsedTime);
    Console.ReadLine();
}
public async Task asyncList()
{
秒表秒表=新秒表();
秒表。开始();
for(int i=0;iMailingFunction());
currentMailAddress=“”;
WriteLine(“您发送给{0}的邮件已成功发送!”,emailingList[i]);
}
秒表;
TimeSpan ts=秒表。已用时间;
string elapsedTime=string.Format(“{0:00}:{1:00}:{2:00}.{3:00}”,
时、分、秒、毫秒/10);
Console.WriteLine(“完成时间”+elapsedTime);
Console.ReadLine();
}

MailingFunction()
是一个简单的SmtpClient和邮件消息

使用
System.Threading.Tasks
命名空间中的
Parallel.ForEach
。因此,对于int i=0;
使用
Parallel.ForEach(emailingList,地址=>{…})


有关示例,请参见
系统.Threading.Tasks
命名空间中的使用
并行.ForEach
。因此,对于int i=0;
使用
Parallel.ForEach(emailingList,地址=>{…})


请参见示例,您的解决方案实际上没有并行运行,因为您等待每个发送操作。您可以使用paralel foreach/for关键字。否则,您必须在执行所有发送操作之后等待

public async Task asyncStartList()
{
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();

    // option 1
    Task[] tasks = emailingList.Select(s => Task.Run(() => { SendEmail(s); }).ToArray();

    Task.WaitAll(tasks);
    // option 1 end

    // option 2
    Parallel.ForEach(emailingList, email =>
    {
        SendEmail(email);
    });
    // option 2 end

    // option 3
    Parallel.For(0, emailingList.Length, i =>
    {
        SendEmail(emailingList[i]);
    });
    // option 3 end

    stopWatch.Stop();
    TimeSpan ts = stopWatch.Elapsed;

    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

    Console.WriteLine("Time for completion " + elapsedTime);
    Console.ReadLine();
}

private void SendEmail(string emailAddress)
{
    // Do send operation
}

您的解决方案实际上不是并行运行的,因为您等待每个发送操作。您可以使用paralel foreach/for关键字。否则,您必须在执行所有发送操作之后等待

public async Task asyncStartList()
{
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();

    // option 1
    Task[] tasks = emailingList.Select(s => Task.Run(() => { SendEmail(s); }).ToArray();

    Task.WaitAll(tasks);
    // option 1 end

    // option 2
    Parallel.ForEach(emailingList, email =>
    {
        SendEmail(email);
    });
    // option 2 end

    // option 3
    Parallel.For(0, emailingList.Length, i =>
    {
        SendEmail(emailingList[i]);
    });
    // option 3 end

    stopWatch.Stop();
    TimeSpan ts = stopWatch.Elapsed;

    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

    Console.WriteLine("Time for completion " + elapsedTime);
    Console.ReadLine();
}

private void SendEmail(string emailAddress)
{
    // Do send operation
}

如果您的解决方案的性能很好,那就是您希望使用并行线程的时候。如果您的解决方案受到其他因素的约束,例如电子邮件服务器处理请求的能力,那么您实际应该使用的是
async
,它更简单、更安全

在这种情况下,有许多方法可以使用异步,但这里有一个简短而简单的模式可以使用:

await Task.WhenAll
(
    emailingList.Select( async address => MailingFunctionAsync(address) )
);
是的,就这些。这假设您的电子邮件客户端不仅有一个
MailingFunction()
方法,还有一个
mailingfunctionsync()
方法(例如,使用Outlook的方法或类似方法)

以下是一个示例
mailingfunctionsync()
从以下位置被盗:


如果您的解决方案的性能很好,那就是您希望使用并行线程的时候。如果您的解决方案受到其他因素的约束,例如电子邮件服务器处理请求的能力,那么您实际应该使用的是
async
,它更简单、更安全

在这种情况下,有许多方法可以使用异步,但这里有一个简短而简单的模式可以使用:

await Task.WhenAll
(
    emailingList.Select( async address => MailingFunctionAsync(address) )
);
是的,就这些。这假设您的电子邮件客户端不仅有一个
MailingFunction()
方法,还有一个
mailingfunctionsync()
方法(例如,使用Outlook的方法或类似方法)

以下是一个示例
mailingfunctionsync()
从以下位置被盗:


我只是觉得我会参与其中。这里常见的答案是使用
Parallel.ForEach
(除了John Wu的答案之外,您还应该考虑)。虽然从一开始,
Parallel.ForEach
似乎是一个简单而好的主意,但它实际上并不是最理想的方法

问题就在这里

Parallel.ForEach
使用线程池。此外,IO绑定操作将阻止那些等待设备响应并占用资源的线程

  • 如果您有CPU绑定的代码,并行性是合适的
  • 虽然如果您有IO绑定的代码,异步是合适的
在这种情况下,发送邮件显然是I/O,因此理想的消费代码应该是异步的

而且

要正确使用.NET的异步和并行功能,还应该理解I/O线程的概念

  • 并非程序中的所有内容都会占用CPU时间。当线程试图从磁盘上的文件读取数据或通过网络发送TCP/IP数据包时,它所做的唯一事情就是将实际工作委托给设备;磁盘或网络适配器;等待结果

  • 花一段时间等待是非常昂贵的。即使线程处于休眠状态,并且在等待结果时不消耗CPU时间,也不会真正得到回报,因为这是对系统资源的浪费

  • 简单地说,每个线程都为堆栈变量、本地存储等保留内存。而且,线程越多,在它们之间切换所需的时间就越长

尽管如此,
Parallel.ForEach
的优点在于易于实现,您还可以设置诸如最大并行度之类的选项

那么你能做什么

您最好使用
async
/
await
模式和/或对并发任务的某种类型的限制,另一个简洁的解决方案是在库中使用

数据流示例

var block = new ActionBlock<MySomething>(
    mySomething => MyMethodAsync(mySomething),
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 50 });

foreach (var something in ListOfSomethings)
{
    block.Post(something );
}

block.Complete();
await block.Completion;
var block=新动作块(
mySomething=>MyMethodAsync(mySomething),
新的ExecutionDataflowBlockOptions{MaxDegreeOfParallelism=50});
foreach(在某物列表中为某物赋值)
{
(某物);
}
block.Complete();
等待区块完成;
这种方法提供了异步性,还提供了
MaxDegreeOfParallelism
,它不会浪费资源,并且让IO成为IO而不会占用不必要的资源

免责声明,数据流可能不在您想要的位置,但是我想我会给您一些关于不同领域的更多信息 提供的方法


我只是觉得我会参与其中。这里常见的答案是t