6

我有一个要向其引入TPL功能的 Windows 应用程序。场景是我有一个类,该类的Process方法具有MailMessage传递给它的 s 集合以及当前 IMAP 连接(使用 AE.Net.Mail)。

我想将尽可能多的线程分拆给Execute另一个类中的一个方法,该方法采用单个MailMessage项目,然后分拆MailMessage到数据库,然后使用 IMAP 连接MailMessage从服务器中删除。

我不太担心跟踪流程 - 我正在处理大量电子邮件,并且不担心我在写入数据库或删除时遇到一些错误。我只需要应用程序尽快通过大量 MailMessages。

我一直在玩,Task<MailMessage>.Factory.StartNew但我真的不知道我在做什么。我似乎无法启动它......这是我尝试过的:

Task test = Task.Factory.StartNew(() =>
{
  foreach (var mailMessage in _mms)
  {
    new ProcessMessage().Execute(mailMessage, imapConn);
  }

});

我很确定我不应该在 lamda 表达式中有一个循环,当我运行它时它似乎没有进入ProcessMessage.Execute.

4

5 回答 5

4

现在您正在将 foreach 循环作为单独的任务执行,但您可能希望将每个迭代作为单独的任务执行。您应该尝试 Parallel.ForEach:

        Parallel.ForEach(_mms, mailMessage =>
            {
                new ProcessMessage().Execute(mailMessage, imapConn);
            });

这将并行执行迭代,这似乎是您想要做的。

于 2012-12-18T14:03:04.293 回答
4

你绝对不应该在你的 lamdba 表达式中有一个循环。尝试这个:

_mms.ForEach(mms => {
    Task.Factory.StartNew(() => ProcessMessage().Execute(mailMessage, imapConn))
});

如果您不担心跟踪结果或不需要保存任务实例的任何内容,例如 Task test = .... 您可以使用Task.Factory.StartNew()这种方式在新线程中启动方法执行只需为您要处理的每条邮件消息启动一个新任务,并让线程池为我们处理事情。

此外,Task<MailMessage>.Factory.StartNew将用于在另一个返回 MailMessage 的线程中设置方法调用,因此如果您正在调用 void 方法,则无需执行此操作。Task<object>语法总是指您使用新任务启动的方法的返回类型。

于 2012-12-18T14:00:16.590 回答
1

当我运行它时,它似乎没有进入ProcessMessage.Execute.

那么您的代码肯定有其他问题,您的代码当然应该可以工作。如果您不想(或不能)并行化代码,则在 lambda 中使用循环可能是完全合适的。

如果您确实想要并行化它(从您的问题中并不清楚),您可以使用例如Parallel.ForEach()为此进行了优化的示例。

于 2012-12-18T15:49:14.803 回答
1

这应该在单独的线程中执行每个执行(所以你知道你现在在做什么:))

  foreach (var mailMessage in _mms)
  {
     ThreadPool.QueueUserWorkItem(delegate
     {
        new ProcessMessage().Execute(mailMessage, imapConn);
     });
  }

或者

  foreach (var mailMessage in _mms)
  {
      new Thread(delegate() { new ProcessMessage().Execute(mailMessage, imapConn); }).Start();
  }
于 2012-12-18T14:00:33.077 回答
1

另一种选择是在集合上使用.AsParallel()和:.ForAll()

_mms.AsParallel()
    .ForAll(mm => ProcessMessage().Execute(mm, imapConn));
于 2012-12-18T14:06:24.207 回答