Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-threading to speed up an email-sending application

I have built an application to send email mailers for a website through Amazon SES. It is coded in C#.

Each email takes .3 seconds to send via the Amazon SES API. That means, using a single-threaded application, I can only send 3 emails per second.

I have implemented a producer/consumer, multi-threaded application with 1 producer to query customize the emails for each customer, and 25 consumers to pull from the queue and send the emails.

My multi-threaded application sends 12 emails per second (a quadruple speed increase). I would have expected a greater speed increase from a 25-thread application.

My question is: How much can I really speed up the sending of a mailer on a single-processor machine? Do my gains seem reasonable, or is my speed problem more likely due to coding than to the computer's inability to process the emails mroe quickly?

Thanks in advance!

UPDATE: In case others are facing the same issue.... connecting to AWS in order to send the email takes up a lot of time. The following thread on AWS Developer forums gives some insight (You may need to scroll down to get to the more useful posts).

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

like image 610
Rebecca Avatar asked Jan 01 '12 23:01

Rebecca


2 Answers

You can speed up very much even though it's single-processor machine.

Sending an Email does not consume a lot of CPU, it's an IO bound operation. Therefore you will increase your performance very much by doing the work in parallel.

like image 78
Maxim Avatar answered Sep 21 '22 06:09

Maxim


I blogged about my solution. Basically you use a Parallel.ForEach loop with a MaxDegreeOfParallelism, don't forget to increase the maxconnection count in app.config.

Below is the app.config sample:

<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>

And here is the Parallel.ForEach loop sample:

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

My blog explains it in more detail: http://michaeldimoudis.com/blog/2013/5/25/reliably-and-speedily-send-mass-emails-via-amazon-ses-in-c

like image 37
dimoss Avatar answered Sep 22 '22 06:09

dimoss