【问题标题】:Threads inside a foreach loop in c#c#中foreach循环内的线程
【发布时间】:2010-01-05 11:23:21
【问题描述】:

大家好,

我有以下代码在我的 asp.net Web 应用程序中向不同用户发送不同的邮件

foreach (DataRow dataRow in dataTable.Rows) 
{
   sendMails();
}
public void sendMails()
{
 //mail code
}

现在我想在 foreach 循环中使用线程,但我不知道结果是什么,因为如果我启动“n”个线程,线程池会发生什么情况。考虑我的数据表包含 1000 行,

是否可以同时运行 1000 个线程?

foreach (DataRow dataRow in dataTable.Rows) 
{
    ThreadStart ts1 = new ThreadStart(sendMails);
    Thread thread1 = new Thread(ts1);
    thread1.Start();
}

public void sendMails()
{
   //mail code
}

【问题讨论】:

  • 可能-是的,明智的没有。

标签: c# asp.net multithreading


【解决方案1】:

启动一个线程来完成发送所有邮件的工作:

new Thread(() => {
    foreach (DataRow dataRow in dataTable.Rows) 
    {
        sendMails();
    }
}).Start();

【讨论】:

  • 考虑将此作业排队到线程池,而不是手动实例化线程。
  • 我认为我不会将线程池线程用于像这样可能长期存在的工作。在这种情况下,启动一个新线程的开销可能比发送所有邮件的开销要小很多。线程池更适合运行时间短、调度频繁的作业。两者都可以。
【解决方案2】:

使用您拥有的代码,线程池什么都不会发生 - 您将完全在线程池之外创建新线程。

您确定要为每封邮件使用一个线程 - 甚至是多个线程吗?我想您会受到与本地 SMTP 服务器的连接的限制,并且启动多个线程对此无济于事。

如果使用线程的目的是能够向用户返回一个页面说“是的,我现在正在发送邮件,那么启动一个线程在后台发送所有内容(根据 Darin 的建议)更明智。”另一方面,这确实意味着如果该过程因某种原因停止,您最终可能只发送了其中的一半。另一种选择(如 Charlie 所建议的)是使用排队系统(例如文件、数据库或 MSMQ)。这样你就可以阻塞直到你排队所有的邮件,这意味着当你返回给用户时,你可以确信数据是“安全的”——但你可以做实际的邮件发送具有可能更强大的服务的背景。

【讨论】:

  • @jon 当我的按钮点击被触发时,完成我的邮件处理需要很多时间.. 任何建议
【解决方案3】:

使用带有单独 Windows 服务的消息队列来发送电子邮件不是更明智吗?

【讨论】:

    【解决方案4】:

    不要创建自己的线程,拥有 1000 个线程意味着 CPU 将所有时间都用于在它们之间切换,而实际执行任何工作的时间很少。

    使用线程池来执行此操作,它将执行多达 25 个(默认情况下)后台线程,并且可以在它们都忙时自动阻塞。

    MSDN tutorial

    【讨论】:

      【解决方案5】:

      也许为此使用线程池更明智,甚至使用 .NET 4.0(或 Parallel FX)中的 Parallel Linq:

      dataTable.Rows.AsParallel().Select(a =>
      {
          //mail code
          return null;
      });
      

      【讨论】:

        【解决方案6】:

        正如许多人所解释的那样,每封电子邮件线程并不是最好的主意,但是如果您决定创建一个后台线程来处理所有电子邮件,则线程运行时间将被限制为 110 秒。 ASP.NET 在 .NET 2.0 中默认将线程执行时间限制为 110 秒。 http://msdn.microsoft.com/en-us/library/e1f13641(v=vs.80).aspx

        创建队列(正如其他人在之前的回复中所建议的那样)更加明智和可扩展。

        http://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.executiontimeout.aspx

        【讨论】:

          【解决方案7】:

          这样构造你的方法可能会更好:

          public void SendMails(DataTable dt)
          {
              foreach (DataRow row in dt.Rows)
              {
                  // send emails
              }
          }
          

          然后这样称呼它:

          SendMails(dataTable);
          

          或者使用BackgroundWorker 调用该方法,这样您的用户界面就不会被锁定。

          【讨论】:

          • @MusiGenesis- 我不认为你见过 ASP.NET 标签
          【解决方案8】:

          第一点是,如果你像这样显式地创建线程,你并没有使用线程池。 CLR 将通过创建所有这些线程来完成任务,即使它最终会创建太多并拖累自己。 1000 个显式线程方式太多了。

          您尝试在另一个线程上执行此操作是因为您希望它异步发生,还是因为您实际上希望多个线程执行发送?

          如果是前者,请尝试以下操作:

          ThreadStart ts1 = new ThreadStart(sendMails);
          Thread thread1 = new Thread(ts1);
          thread1.Start();
          
          public void sendMails()
          {
             foreach (DataRow dataRow in dataTable.Rows) 
             {
                //mail code
             }
          }
          

          如果您确实觉得通过一些多线程可以提高发送性能,那么您需要手动限制在任何时候创建的线程数,或者使用 .Net 线程池,因为这会让您排队在线程空闲之前将阻塞的工作项。这当然比创建大量显式线程更可取。

          【讨论】:

            猜你喜欢
            • 2021-06-01
            • 1970-01-01
            • 1970-01-01
            • 2016-09-26
            • 2012-07-19
            • 1970-01-01
            • 2018-08-10
            • 1970-01-01
            • 2016-12-31
            相关资源
            最近更新 更多