【问题标题】:Multithreaded foreach多线程 foreach
【发布时间】:2013-10-16 06:33:38
【问题描述】:

我有一个数据集中的 ReferenceID(字符串)列表。这些 ReferenceID 可以具有这样的值 ("CQ1258891","CQ1258892","CQ1258893"....""CQ1258993")。我的代码中有一个逻辑可以为每个 ReferenceID 发送邮件。

到目前为止,我正在同步循环遍历每个 ReferenceID。因此,发送每封邮件需要更多时间。 我一直在使用 .NET 3.0,所以我没有选择在 .NET 4.0 中使用 TPL。

我一直在寻找一种多线程机制来异步发送每个 ReferenceID 的邮件。到目前为止,我已经尝试了以下代码,但它没有按预期工作。

foreach (DataRow row in qrefSet.Tables[0].Rows)
{
    string refId = Convert.ToString(row["ReferenceID"]);
    if (!string.IsNullOrEmpty(refId))
    {
        Thread thread = new Thread(() => apeDBAdapter.SendEmail(personId, refId, parentReferenceID, customerName, queueId));                                    
        thread.Start();
    }
}

请分享为我的实现实现多线程foreach循环的有效机制。

谢谢, 斯里拉姆

【问题讨论】:

  • 为什么不使用线程池中的线程?阅读msdn.microsoft.com/en-us/library/… - 让他们做线程管理的工作
  • 您至少应该升级到 .NET 3.5。 “对 3.5 SP1 之前的 .NET Framework 3.x 版本的支持将一直支持到 2011 年 7 月 12 日。在此日期之后,支持将终止;我们强烈建议客户在 2011 年 7 月 12 日之前迁移到 .NET Framework 3.5 SP1。 "
  • 在.NET 3.5的情况下,将如何实现?我很想知道这样做的正确方法。
  • 创建线程很昂贵。使用 ThreadPool.QueueUserWorkItem 将您的作业排队
  • ilansch & Carlos,我尝试了 ThreadPool.QueueUserWorkItem。我有多个参数要传递,但这个方法只需要两个参数。无法传递剩余参数!知道我该怎么做吗?这些是我的参数(personId、refId、parentReferenceId、customerName、queueId)

标签: c# multithreading .net-3.0


【解决方案1】:

试试这个

foreach (DataRow row in qrefSet.Tables[0].Rows)
{
    string refId = Convert.ToString(row["ReferenceID"]);
    if (!string.IsNullOrEmpty(refId))
    {
        Thread thread = new Thread(new ParameterizedThreadStart(SendMail));
        thread.Start(refId)           
    }
}
..........
void SendMail(object refId)
{
    string strRefId = (string)refId;
    apeDBAdapter.SendEmail(personId, refId, parentReferenceID, customerName, queueId));  
}

希望对你有帮助……

【讨论】:

  • 但他要求并行 foreach...而不是实际发送。
  • 如果他使用 TPL,foreach 可以并行,但不幸的是,这对他来说是不可能的......所以这是我建议给他的选项。
  • 那么例如如果有1000个引用,就会启动1000个线程?
  • 这取决于,如果会有更多的行......那么我们需要找到其他方法......问题中没有提到行的数量。
【解决方案2】:

您可以创建一个方法,从 rows 集合中获取一系列项目,并根据 devision 的数量多线程运行它。

例如:

SendEmailsToReferencesByRange(int start, int end, DataRowCollection rows)
{
  foreach(var item in rows.Range(start, end-start))
  {
     //Do your sending logic here
  }
}

用法:

//if for example you have 200 items than you can run it in 2 threads
Thread thread = new Thread(()=>SendEmailsToReferencesByRange(0,100, table[0].Rows)).Start();
Thread thread = new Thread(()=>SendEmailsToReferencesByRange(100,200, table[0].Rows)).Start();

【讨论】:

    【解决方案3】:

    你可以使用这个结构来做到这一点。它使用 ThreadPool,所以它不会创建很多线程,虽然 更好 的想法是使用 APM 发送电子邮件,因此不会浪费线程。

    等待所有后台操作完成。 data 是数据集的行。

    int opsLeft = data.Count();
    using (var mre = new ManualResetEvent(false))
    {
        foreach (DataRow row in data)
        {
            string refId = Convert.ToString(row["ReferenceID"]);
            if (!string.IsNullOrEmpty(refId))
            {
                ThreadPool.QueueUserWorkItem(_ =>
                {
                    apeDBAdapter.SendEmail(personId, refId, parentReferenceID, customerName, queueId);
                    if (Interlocked.Decrement(ref opsLeft) == 0)
                        mre.Set();
                });
            }
            else
            {
                if (Interlocked.Decrement(ref opsLeft) == 0)
                    mre.Set();
            }
        }
        mre.WaitOne();
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      • 1970-01-01
      • 2012-07-27
      • 2013-09-27
      • 2015-02-17
      • 1970-01-01
      相关资源
      最近更新 更多