多线程加速电子邮件发送应用程序

时间:2012-01-01 23:08:58

标签: c# multithreading performance amazon-web-services producer-consumer

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

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

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

我的多线程应用程序每秒发送12封电子邮件(速度提高四倍)。我原本期望从25线应用程序中获得更大的速度提升。

我的问题是: 我可以在单处理器计算机上真正加快发送邮件的速度吗?我的收益是否合理,或者我的速度问题更可能是由于编码而不是计算机无法快速处理电子邮件?

提前致谢!

更新:如果其他人面临同样的问题....连接到AWS以发送电子邮件需要花费大量时间。 AWS Developer论坛上的以下主题提供了一些见解(您可能需要向下滚动才能获得更有用的帖子)。

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

8 个答案:

答案 0 :(得分:4)

即使它是单处理器的机器,你也可以加速。

发送电子邮件消耗大量 CPU ,它是 IO绑定操作。 因此,通过并行工作,您将大大提高您的表现。

答案 1 :(得分:3)

我在博客上写了我的解决方案。基本上,您使用Parallel.ForEach循环MaxDegreeOfParallelism,不要忘记增加maxconnection中的app.config计数。

以下是app.config示例:

<system.net>
    <connectionManagement>
        <add address="*" maxconnection="392" />
    </connectionManagement>
    <mailSettings>
        <smtp from="form@company.com" 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

答案 2 :(得分:2)

  

我的问题是:我能真正加快发送邮件的速度   在单处理器机器上?我的收益是否合理,或者是我的   速度问题更可能是由于编码而不是计算机的问题   无法更快地处理电子邮件?

从广义上讲,线程数增加25倍的速度提升4倍并不算太大,但它也不是很好。

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

虽然我没有使用Amazon SES,但我知道其他亚马逊产品肯定会使用各种形式的带宽/请求限制。可能(可能)您的吞吐量受亚马逊的限制比您的应用程序更多。

我不久前写了一个高性能的批量邮件应用程序,我做的是:

  1. 除多线程外,尽可能使用异步I / O.这样,如果一个请求很慢,它就不会占用整个线程。
  2. 将电子邮件直接发送到终端服务器,而不是通过中间网关。这需要使用P / Invoke调用DNS来检索必需的MX或A记录。之后,我使用标准SmtpClient类(具有SendAsync方法)来实际发送邮件。
  3. 此方法还允许我在发送邮件时查看和记录错误,从而为用户提供更好的反馈。另一种方法是依靠从网关服务器接收和解析错误邮件,这很容易出错。

答案 3 :(得分:1)

在多核(或多处理器)系统上运行的多线程应用程序中,黄金法则是(通常)无法实现比顺序执行时间的N倍更好的加速,其中N是核心数。因此,如果您的活动需要12秒,并且您在4个核心上并行运行,则总共不能超过3秒。

相反,如果之前您可以在一个单位时间内执行一项活动,则使用4个核心,您将无法在同一时间单位内完成4项活动。

此外,由于通常会影响并行程序性能的几个因素,这个上限并不总能实现:磁盘I / O瓶颈,内存饱和,锁争用等。

答案 4 :(得分:1)

只有一个队列的生产者消费者不能很好地扩展。随着您添加更多消费者或生产者,队列成为瓶颈。

如果您有多处理器架构,则可以使用多个进程发送电子邮件。你仍然可以使用你的生产者消费者多线程版本,但现在它将是一个foreach过程;这将加速一些事情(正如都铎解释的那样)但问题仍然存在。

但是,对于整个系统,您可能只有一个网络管理器或类似实体发送消息(例如htttp消息)和一个网卡。现在瓶颈可能是这个网络管理员。我想了解更多有关系统架构的信息:)

答案 5 :(得分:0)

几个月前,我的情况类似。虽然我们需要很多因素来告诉您导致性能下降的因素,但您可以尝试使用EC2实例的mirco实例来尝试发送电子邮件。

在我的案例中,结果表明这是一个合适的解决方案,因为我正在处理Web应用程序。

答案 6 :(得分:0)

任务既不受CPU限制,也不受IO限制。 该任务向SES发出请求以发送电子邮件(具有有限的数据或IO),然后等待。因此,请使用可用于可用RAM的最大线程数。

答案 7 :(得分:-2)

如何评论,这是一个I / O问题,因为,您需要找到大量具有红外/带宽大小的作业

使用队列模式,

示例:

1 - 排队发送电子邮件

2 - “N”乔布斯发送电子邮件