如何在每个线程中链接任务

时间:2012-12-06 01:10:54

标签: c#-4.0 progress-bar task-parallel-library chain

我需要使用bulkcopy复制数百个表。 到目前为止,我得到了以下代码。

// from UI main thread
private void test1()
{
  LimitedTaskScheduler scheduler = new LimitedTaskScheduler(4);
  TaskFactory factory = new TaskFactory(scheduler);
  foreach (DataRow row in tabList.Rows) // Loop over the rows.
  {
    string tabName = row[tabList.Columns["TableName"]].ToString();
    factory.StartNew<string>( () =>
    {
      Console.WriteLine("{0} on thread {1}", tabName, Thread.CurrentThread.ManagedThreadId);
      TableCopyer tc1 = new TableCopyer();
      // pass progressbar and label into tc1 instance to update the progressbar and label
      tc1.Bar1 = bar1; 
      tc1.L1 = l1;
      tc1.EntityCopy(AppInfo.SrcDBMSPath, AppInfo.DestDBMSPath, tabName, "");
      return tabName;
    });
  }
}

// inside TableCopier class
private void OnSqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
{
  try
  {
    int rowCopied = int.Parse(e.RowsCopied.ToString());
    double result = (double.Parse(rowCopied.ToString()) / double.Parse(TotalRows.ToString()));
    int prsent = int.Parse(Math.Round((result * 100), 0).ToString());
    SetProgressbar(prsent);
  }
  catch { throw; }
}

LimitedTaskScheduler来自 http://msdn.microsoft.com/en-us/library/ee789351.aspx

我的问题是

  1. 如何将任务链接起来,以便每个任务只在每个线程中完成前一个任务后启动?我将最大并行线程限制为4.我想在线程中链接任务,因为在线程中执行的任务将以一个完成而另一个开始的方式重用相同的进度条。

  2. 我在UI,bar1,bar2,bar3,bar4上绘制了4个进度条。如何将每个进度条与特定线程相关联,以便用户可以同时看到4个正在运行的进度?

2 个答案:

答案 0 :(得分:0)

我认为将自己与特定线程联系起来没有多大意义。相反,你想要的是你的任务最多同时运行4个,你想要使用这些任务中的4个进度条。

你可以做的是将这些进度条放入一个集合中,然后在每个任务开始时从那里取一个进度条,并在任务结束时将其返回到那里。

这里你必须小心线程安全,所以你应该在使用进度条集合时使用锁,或者使用像ConcurrentQueue这样的线程安全集合。此外,更新进度条通常必须从UI线程完成,因此您也必须处理它。

答案 1 :(得分:-1)

  

如何将任务链接起来,以便每个任务仅在完成后启动   每个线程中的先前任务?我限制了最大平行   线程到4.我想在线程中链接任务,因为   在线程中执行的任务将重用相同的进度条   在一种方式完成,另一种开始。

您希望将任务链接在一起。所以基本上没有并行处理发生,除了你希望在与UI分开的线程上处理它。那么,如果你不想循环处理顺序运行,为什么还要为循环的每次迭代生成一个新任务呢?您可以在任务中包含正常的for循环:

private void test1()
{
    Task.Factory.StartNew(() =>
    {
        foreach (DataRow row in tabList.Rows) // Loop over the rows.
        {
            string tabName = row[tabList.Columns["TableName"]].ToString();

            Console.WriteLine("{0} on thread {1}", tabName, Thread.CurrentThread.ManagedThreadId);
            TableCopyer tc1 = new TableCopyer();
            // pass progressbar and label into tc1 instance to update the progressbar and label
            tc1.Bar1 = bar1;
            tc1.L1 = l1;
            tc1.EntityCopy(AppInfo.SrcDBMSPath, AppInfo.DestDBMSPath, tabName, "");
        }
    });
}
  

我在UI,bar1,bar2,bar3,bar4上画了4个进度条。我如何能   将每个进度条与特定线程关联以便用户   可以同时看到4个运行进度吗?

有很多方法可以做到这一点,这实际上取决于您对哪种方法最好的要求。您可以在Queue<T>中引用进度条,但前提是您确信您将拥有与表行一样多的进度条。

private void test1()
{
    Task.Factory.StartNew(() =>
    {
        var progressBars = new Queue<ProgressBar>(new List<ProgressBar> { bar1, bar2, bar3, bar4 });

        foreach (DataRow row in tabList.Rows) // Loop over the rows.
        {
            // ...

            if(progressBars.Count() == 0}
                throw new Exception("Not enough progress bars setup!");

            tc1.Bar1 = progressBars.Dequeue();

            // ...
        }
    });
}

如果tabList.RowsIEnumerable,那么您可以使用Take()确保队列不会中断:

foreach (DataRow row in tabList.Rows.Take(progressBars.Count()))
{ ... }