Многопоточность для ускорения работы приложения для отправки электронной почты - PullRequest
8 голосов
/ 02 января 2012

Я создал приложение для отправки почтовых программ на сайт через Amazon SES. Это закодировано в C #.

Каждое электронное письмо занимает 0,3 секунды для отправки через API Amazon SES. Это означает, что с помощью однопоточного приложения я могу отправлять только 3 электронных письма в секунду.

Я реализовал многопоточное приложение «производитель / потребитель», в котором 1 производитель запрашивает индивидуальную настройку электронной почты для каждого клиента, а 25 потребителей извлекают из очереди и отправляют электронные письма.

Мое многопоточное приложение отправляет 12 электронных писем в секунду (увеличение в четыре раза). Я ожидал бы большего увеличения скорости от приложения с 25 потоками.

Мой вопрос: Насколько я могу ускорить отправку почтовой программы на однопроцессорной машине ? Кажется ли мой выигрыш разумным или моя проблема со скоростью скорее связана с кодированием, чем с неспособностью компьютера быстро обрабатывать электронные письма?

Заранее спасибо!

ОБНОВЛЕНИЕ: В случае, если другие сталкиваются с той же проблемой .... подключение к AWS для отправки электронного письма занимает много времени. Следующая ветка на форумах разработчиков AWS дает некоторую информацию (возможно, вам придется прокрутить вниз, чтобы перейти к более полезным сообщениям).

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

Ответы [ 8 ]

4 голосов
/ 02 января 2012

Вы можете очень сильно ускориться, даже если это однопроцессорный компьютер.

Отправка электронной почты не потребляет много CPU , это IO связанный операция.Поэтому вы значительно повысите свою производительность, выполняя работу параллельно.

3 голосов
/ 03 июня 2013

Я написал в блоге о своем решении. В основном вы используете цикл 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 голосов
/ 02 января 2012

Мой вопрос: насколько я могу ускорить отправку почтовой программы на однопроцессорной машине?Кажется ли мой выигрыш разумным, или моя проблема со скоростью скорее из-за кодирования, чем из-за неспособности компьютера обрабатывать электронные письма быстрее?это не возмутительно, но и не здорово.

Узкий процессор станет узким местом только при высокой загрузке вашего процессора.Вы можете определить, является ли это проблемой для вас, посмотрев на общую загрузку ЦП во время работы вашего приложения.Теоретически, отправка электронных писем должна быть операцией с ограниченным вводом / выводом;если это не так, то у вашего кода могут быть проблемы.

Хотя я не использовал Amazon SES, я знаю, что другие продукты Amazon определенно используют различные формы регулирования пропускной способности / запросов.Возможно (вероятно), что ваша пропускная способность больше ограничена Amazon, чем вашим приложением.

Некоторое время назад я написал высокопроизводительное почтовое приложение, и я сделал следующее:

  1. Максимально использовал асинхронный ввод / вывод в дополнение к нескольким потокам.Таким образом, если один запрос медленный, он не использует весь поток.
  2. Отправка электронной почты напрямую на конечные серверы, а не через промежуточный шлюз.Это потребовало использования P / Invoke для вызова DNS для получения необходимых записей MX или A.После этого я использовал стандартный класс SmtpClient (который имеет метод SendAsync) для фактической отправки почты.

Этот подход также позволяет мне видеть и записывать ошибки при отправке почты, чтов свою очередь, обеспечивает лучшую обратную связь для пользователей.Альтернативой является получение и анализ сообщений об ошибках от сервера шлюза, который, по меньшей мере, подвержен ошибкам.

1 голос
/ 02 января 2012

производитель-потребитель только с одной очередью плохо масштабируется.Очередь становится узким местом, когда вы добавляете больше потребителей или производителей.

Если у вас многопроцессорная архитектура, вы можете использовать несколько процессов для отправки электронной почты.Вы все еще можете использовать многопоточную версию вашего производителя-потребителя, но теперь это будет один процесс foreach;это немного ускорит процесс (как объяснил Тудор), но проблема остается.

однако для всей системы у вас может быть только один сетевой менеджер или аналогичный объект, который отправляет сообщения (например, сообщения htttp)и одна сетевая карта.Теперь узким местом может быть этот сетевой менеджер.Я хотел бы узнать больше об архитектуре системы:)

1 голос
/ 02 января 2012

В многопоточном приложении, работающем в многоядерной (или многопроцессорной) системе, золотое правило состоит в том, что (как правило) вы не можете добиться лучшего ускорения, чем N раз последовательного выполнения, где N - количество ядер.Поэтому, если у вас есть действие, занимающее 12 секунд, и вы выполняете его параллельно на 4 ядрах, вы не можете сделать лучше, чем всего 3 секунды.

И наоборот, если ранее вы могли выполнить одно действие за одну единицу временис 4 ядрами вы не можете выполнять лучше, чем 4 действия в одну и ту же единицу времени.

Кроме того, эта верхняя граница не всегда достигается из-за нескольких факторов, которые обычно влияют на производительность параллельных программ: дисковый ввод-выводузкие места, насыщение памяти, конфликт блокировки и т. д.

0 голосов
/ 30 января 2017

Задача не связана ни с процессором, ни с IO. Задача отправляет SES запрос на отправку электронного письма (с ограниченными данными или вводом-выводом), а затем ожидает. Таким образом, используйте наибольшее количество потоков, которое вы можете использовать для доступной оперативной памяти.

0 голосов
/ 04 апреля 2013

Я был в похожей ситуации несколько месяцев назад. Хотя есть много факторов, которые нам нужны, чтобы сказать вам, что приводит к снижению производительности, вы можете попробовать с экземпляром mirco экземпляра EC2 попытаться отправить электронную почту.

В моем случае это работало хорошо, и это было подходящее решение, когда я работал над веб-приложением.

0 голосов
/ 02 января 2012

Как прокомментировано, это проблема ввода-вывода, потому что вам нужно найти хорошее количество заданий с размером инфра / пропускной способности

Использовать шаблон очереди,

Пример:

1 - поставить почтовый ящик в очередь

2 - «N» Джобс отправляет электронное письмо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...