8

我已经构建了一个应用程序,通过Amazon SES为网站发送电子邮件邮件。它用C#编码。多线程加速电子邮件发送应用程序

每封电子邮件需要0.3秒才能通过Amazon SES API发送。这意味着,使用单线程应用程序,我只能每秒发送3封电子邮件。

我实现了一个生产者/消费者,多线程应用程序与1个生产者查询定制电子邮件为每一个客户,和25消费者从队列中提取并发送电子邮件。

我的多线程应用程序每秒发送12个电子邮件(四倍速度增加)。我预计25线程应用会提高速度。

我的问题是: 多少钱我可以真的加快发送邮件在单处理器机器?我的收益看起来是否合理,还是我的速度问题更可能是由于编码而非计算机无法快速处理电子邮件?

在此先感谢!

UPDATE:如果其他人遇到同样的问题....连接到AWS以发送电子邮件需要很长时间。 AWS Developer论坛上的以下主题提供了一些见解(您可能需要向下滚动才能看到更有用的帖子)。

https://forums.aws.amazon.com/thread.jspa?threadID=78737

+0

从我对多线程的理解来看,它可以处理多个任务,但仍然需要相同的时间。所以我不认为使用多线程会节省大量时间。但是,如果在电子邮件发送时UI仍然需要可访问,则可以使用多线程。 – craig1231 2012-01-01 23:13:57

+0

您的系统中有多少个核心? – Tudor 2012-01-01 23:14:23

+0

在典型的邮件过程中,队列计数会发生什么情况?查看生产者线程是否超出电子邮件发件人或不是。也许每隔一秒将P-C队列计数转储到计时器的屏幕上。 – 2012-01-02 02:36:48

回答

2

我的问题我s:我能在单处理器机器上加快发送邮件程序 多少钱?我的收益看起来是否合理,或者我的 速度问题更可能是由于编码而不是计算机的 无法更快处理电子邮件?

从广义上讲,线程数增加25倍的4倍加速并不算离谱,但也不算太好。

当CPU使用率很高时,单个CPU只会成为瓶颈。您可以通过查看应用程序运行时的总CPU使用情况来判断这是否是一个问题。理论上,发送大量电子邮件应该是I/O限制操作;如果这不是你的情况,那么你的代码可能有问题。

尽管我没有使用亚马逊SES,但我知道其他亚马逊产品绝对使用各种形式的带宽/请求限制。亚马逊可能(可能)会限制您的吞吐量,而不是您的应用程序。

我写了一个高性能的群发邮件应用程序而回,而我所做的是:

  1. 二手异步I/O尽可能地,除了多线程。这样,如果一个请求很慢,它不会占用整个线程。
  2. 直接发送电子邮件到终端服务器,而不是通过中间网关。这需要使用P/Invoke来调用DNS来检索必需的MX或A记录。之后,我使用标准的SmtpClient类(其具有SendAsync方法)实际发送邮件。

这种方法还可以让我在发送邮件时看到并记录错误,从而为用户提供更好的反馈。另一种方法是依赖于从网关服务器接收并解析错误邮件,这很容易出错,至少可以这样说。

+0

+1 - 到目前为止,这是最能解决问题并提供最详细和具体信息的答案。谢谢!将尝试一些这些建议,并返回到此线程发布结果! – Rebecca 2012-01-03 16:58:47

1

在对多核(或多处理器)上运行多线程应用系统中的黄金法则是,(一般)不能达到比N次的顺序执行的时间,其中N是一个更好的加速核心数量。所以如果你有一个活动需要12秒,并且你在4个核心上并行运行它,你总共不会超过3秒。

相反,如果以前你可以在单个时间单位执行一项活动,4个核心,你不能在相同的时间单位做的更好,然后4个活动。

此外,该上限并不总是能够达到由于几个因素,其通常影响并行程序的性能:磁盘I/O瓶颈,存储器饱和,锁争用等

+1

那么这只适用于CPU有限的问题。即我已经编写了并行查询服务器的代码,比核心数量有更高的加速比(还使用更多的线程)。但没有一些分析瓶颈的地方,我们没有太多的可以说.. – Voo 2012-01-01 23:22:12

+1

这个回答不适用于OP的情况。 – 2012-01-02 00:28:07

1

生产者消费者只用一个队列没有很好的规模。添加更多消费者或生产者时,队列成为瓶颈。

如果你有多处理器架构,您可以使用多个进程来发送电子邮件。你仍然可以使用你的生产者消费者多线程版本,但现在它将成为一个foreach过程;这会加快速度(正如Tudor解释的),但问题仍然存在。

然而,你可能有,对于整个系统,只有一个发送邮件(比如HTTTP消息)网络管理器或类似实体和一个网卡。现在瓶颈可能是这位网络管理员。我想知道更多关于系统:)

+0

与用于设置TCP连接和发送电子邮件的I/O时间和等待时间相比,在P-C队列活动上花费的时间并不重要。如果队列操作成为这个应用程序的瓶颈,我会很惊讶。 – 2012-01-02 02:30:36

+0

你不能保证生产者不需要很多时间。我同意你,有可能网络管理员是一个瓶颈。然而问题仍然是排队方法不能很好地满足消费者和消费者的需求 – Adrian 2012-01-02 03:27:05

+0

似乎生产者与消费者相比很快完成......这似乎并不是瓶颈,而是一个好点。 – Rebecca 2012-01-03 19:36:46

4

可以加快很多,即使它的单处理器计算机的体系结构。

发送电子邮件确实消耗大量的CPU ,它是一个IO约束操作。 因此,通过并行地完成工作,您将会提高您的表现。

+0

+1,即使单线程处理器上有很多线程I/O等待,也可以大幅加速。 – 2012-01-02 02:27:22

+0

你如何建议并行工作? – 2012-01-02 21:17:34

+0

@SurjitSamra - 不知道你在问什么。他使用了我不熟悉的一些亚马逊API。 – Maxim 2012-01-02 22:56:05

-2

如何评论说,这是一个I/O问题,因为,你需要找到一个很好的任务数与红外/带宽大小

使用队列模式,

例子:

1 - 一个排队投递邮件

2 - “N” 作业调度电子邮件

+1

这没有多大意义。 – Lloyd 2012-01-02 01:37:48

0

几个月前,我的情况相似。尽管我们需要很多因素才能告诉您导致性能较低,但您可以尝试使用EC2实例的mirco实例尝试发送电子邮件。

事实证明,在我的情况下工作得很好,而且在我正在开发Web应用程序时这是一个合适的解决方案。

3

我博客了解我的解决方案。基本上你用一个Parallel.ForEach循环与MaxDegreeOfParallelism,不要忘记增加计数在app.config

下面是app.config样本:

<system.net> 
    <connectionManagement> 
     <add address="*" maxconnection="392" /> 
    </connectionManagement> 
    <mailSettings> 
     <smtp from="[email protected]" deliveryMethod="Network"> 
      <network host="email-smtp.us-east-1.amazonaws.com" userName="SmtpUsername" password="SmtpPassword" enableSsl="true" port="587" /> 
     </smtp> 
    </mailSettings> 
</system.net> 

这里是Parallel.ForEach循环样本:

class Program 
{ 
    static readonly object syncRoot = new object(); 
    private readonly static int maxParallelEmails = 196; 

    static void Main(string[] args) 
    { 

     IList<Model.SendEmailTo> recipients = _emailerService.GetEmailsToSend(); 
     int cnt = 0; 
     int totalCnt = recipients.Count; 


     Parallel.ForEach(recipients.AsParallel(), new ParallelOptions { MaxDegreeOfParallelism = maxParallelEmails }, recipient => 
     { 
      // Do any other logic 

      // Build the email HTML 

      // Send the email, make sure to log exceptions 

      // Track email, etc 

      lock (syncRoot) cnt++; 
      Console.WriteLine(String.Format("{0}/{1} - Sent newsletter email to: {2}", cnt, totalCnt, recipient.Email)); 
     }); 
    } 
} 

我的博客解释了它的详细信息:http://michaeldimoudis.com/blog/2013/5/25/reliably-and-speedily-send-mass-emails-via-amazon-ses-in-c

0

的任务既不是CPU绑定,也不受IO限制。 该任务向SES发送一封电子邮件(带有限数据或IO),然后等待。因此,使用可用RAM的最大线程数。

相关问题