Как я могу отправить MailMessages, используя несколько потоков? - PullRequest
3 голосов
/ 24 февраля 2011

Я надеюсь, что вы, ребята, будете терпеть меня из-за моего полного отсутствия направления в случае с Threading.Мне нужно внедрить систему обработки почтовых очередей, в которой я должен отправлять электронные письма, помещенные в очередь в базе данных через службу Windows.

Это не шаблон производителя-потребителя.Я получил, скажем, 10 строк за раз в таблицу данных.Таблица данных содержит сериализованный объект MailMessage и сведения об отправке SMTP.Если мне нужно использовать, скажем, фиксированное количество потоков (скажем, 6 потоков), то теперь, как мне будет выбрать строку из таблицы данных в потоке, а затем отправить письмо и снова вернуться, чтобы увидеть, остались ли еще строки?*

Подойдет любая простая логика для реализации, желательно с простым примером на C #.

Я использую .NET 3.5

Ответы [ 2 ]

5 голосов
/ 24 февраля 2011

Поскольку отправка электронной почты является процессом, связанным с вводом / выводом, поэтому создание потоков для отправки электронной почты не приведет к значительному (если вообще потребуется) ускорению.

Если вы используете SMTP-сервер, который является частью Windows, токогда вы «отправляете» электронное письмо, оно фактически не отправляется в этот момент.Он находится в очереди на сервере, и сервер отправляет их так быстро, как может.Отправка электронных писем на самом деле является медленным процессом.

Я предполагаю, что я имею в виду два варианта:

  1. Просто отправляйте их последовательно и посмотрите, соответствует ли это вашим требованиям к производительности.
  2. Вы могли бы использовать концепцию параллельного программирования под названием «Параллельная передача данных». Я продемонстрировал ее на примерах в блоге Параллельная передача данных - параллельное программирование на C # /. NET

По сути, вы получаете все свои данные (за один раз).Причина в том, что получение данных в пакетах также замедляет ваш процесс, поэтому, если вы заинтересованы в производительности (именно поэтому я предполагаю, что вы пытаетесь использовать потоки), то не выполняйте многократные обходы на сервер базы данных.(который также связан с вводом / выводом на двух уровнях: сетевой ввод / вывод и дисковый ввод / вывод).

Получите ваши данные и разбейте их на куски или разделы.Это все объясняется в статье, на которую я указал.Наивной реализацией будет количество чанков, равное количеству ядер на машине.

Каждый чанк обрабатывается одним потоком.Когда все темы сделаны, все готово.С новыми функциями ThreadPool в .NET 4.0 (если вы используете Parallel.For или PLINQ или Tasks) вы получите некоторые другие преимущества, такие как «похищение работы» для дальнейшего ускорения работы.

Parallel.Я думаю, что / Parallel.ForEach будет хорошо работать для вас.

EDIT

Только что заметил требование .NET 3.5.Ну, концепции все еще применяются, но у вас нет Parallel.For / ForEach.Итак, вот реализация (измененная из моего сообщения в блоге), которая использует ThreadPool и использует метод параллельной передачи данных.

    private static void SendEmailsUsingThreadPool(List<Recipient> recipients)
    {
      var coreCount = Environment.ProcessorCount;
      var itemCount = recipients.Count;
      var batchSize = itemCount / coreCount;

      var pending = coreCount;
      using (var mre = new ManualResetEvent(false))
      {
        for (int batchCount = 0; batchCount < coreCount; batchCount++)
        {
          var lower = batchCount * batchSize;
          var upper = (batchCount == coreCount - 1) ? itemCount : lower + batchSize;
          ThreadPool.QueueUserWorkItem(st =>
          {
            for (int i = lower; i < upper; i++)
              SendEmail(recipients[i]);
            if (Interlocked.Decrement(ref pending) == 0)
              mre.Set();
          });
        }
        mre.WaitOne();
      }      
    }

    private static void SendEmail(Recipient recipient)
    {
      //Send your Emails here
    }
  }

  class Recipient
  {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddress { get; set; }
  }

Итак, получите ваши данные и вызовите SendEmailUsingThreadPool (), передав их вашим данным.Конечно, не называйте свой метод так :).Если у вас есть DataSet / DataTable, просто измените реализацию, чтобы принять DataSet / DataTable.Этот метод позволяет разделить ваши данные на куски, чтобы вам не приходилось беспокоиться об этом.Просто позвоните.

0 голосов
/ 24 февраля 2011

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

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