并行线程和控制?

时间:2012-05-27 04:30:45

标签: c# winforms multithreading .net-4.0 thread-safety

我有这样的功能:

private void GetRSS(int start, int end)
{
    for (int i = start; i < end; i++)
    {
        string content = string.Empty;
        using (WebClient client = new WebClient())
        {
            //some code here get html content
        }
        // some code here parse content
    }
}

为了最大限度地减少运行以获取所有需要数据的时间,我希望同时运行4次不同范围的函数,然后合并结果或使用线程安全列表或字典。< / p>

我的问题是,如何在4个独立的线程中运行此函数,并且仍然可以控制其中一个线程是否仍在工作或不知道它何时结束?

我的第一个想法是声明每个帖子:

private Thread _controler;
private Thread _worker1;
private Thread _worker2;
private Thread _worker3;
private Thread _worker4;
private bool _isRunning = false;

然后我会启动控制器并从控制器内部调用每个线程执行上面的函数并跟踪控制器中的每个线程,如:

private void _ControlerStart()
{
    _worker1 = new Thread(GetRSS);
    try
    {
        _worker1.Start(1, 7711);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
    // repeat the above to all the 4 threads
    _isRunning = true;
    while (_isRunning)
    {
        if (_worker1.ThreadState != ThreadState.Running && _worker2.ThreadState != ThreadState.Running && _worker3.ThreadState != ThreadState.Running && _worker4.ThreadState != ThreadState.Running)
            _isRunning = false;
    }
    MessageBox.Show("Done");
}

在思考上面所有这些混乱的时候,我意识到这不是做我想做的最好的方式,我在这里;)。

如何管理多个线程以运行相同的功能,但是能够知道每个线程何时结束工作以关闭或保存或合并数据或执行其他任何我要做的事情。主线?

3 个答案:

答案 0 :(得分:3)

private static void GetRSS(int start, int end)
{
    var bunchSize = (end - start) / 4 + 1;

    var threads = new List<Thread>();

    for (int i = 0; i < 4; i++)
    {
        var currStart = start + i * bunchSize;
        var currEnd = currStart + bunchSize;

        if (currEnd > end)
        {
            currEnd = end;
        }

        var thread = new Thread(() =>
                                    {
                                        // thread logic using currStart and currEnd

                                        string content = string.Empty;
                                        using (WebClient client = new WebClient())
                                        {
                                            //some code here get html content
                                        }
                                        // some code here parse content
                                    });

        threads.Add(thread);
        thread.Start();
    }

    foreach (var thread in threads)
    {
        thread.Join();
    }
}

答案 1 :(得分:1)

是否有特定原因不使用TPL? http://msdn.microsoft.com/en-us/library/dd460717.aspx

您可能已经注意到,提供的代码的问题在于它不是声明性的。你告诉机器怎么做,而不是你想做什么。

编辑在我的评论中,我建议使用the following code.

在OP的评论中,我看到了

  

我有30k页面可以检索每页上有10条记录的位置,所以我想沿着4个线程拆分30k页面,每个页面在下载到字符串后需要解析

第一部分定义了要执行的动作,第二部分清楚地描述了PC的手持动作。我建议的是停止握住PC的手,并考虑要执行的高级动作。

  1. 要求N页
  2. 当任何一个页面可用时,请使用结果
  3. 当所有N页都可用并消耗时,整理结果
  4. 这需要异步编程。在.NET 4.0中,它主要在F#2.0下提供。 C#4.0可以使用APM和continuation,但我不推荐它。

    C#vNext支持此功能,请参阅VS 2012。

答案 2 :(得分:0)

在任务方式中,您可以使用TaskFactory.ContinueWhenAll Method在所有任务完成后执行某些操作。

    private void ButtonOnClick(object sender, RoutedEventArgs routedEventArgs) {
        const int n = 15;
        var tasks = new Task<int>[n];
        for (int i = 0; i < n; i++) {
            tasks[i] = Task.Factory.StartNew(
                () => {
                    Thread.Sleep(500);
                    return 100;
                });
        }

        Task.Factory.ContinueWhenAll(
            tasks,
            ts => { text.Text = string.Format("Sum: {0}", ts.Sum(task => task.Result)); },
            CancellationToken.None,
            TaskContinuationOptions.None,
            TaskScheduler.FromCurrentSynchronizationContext());
    }

我在这里使用TaskScheduler.FromCurrentSynchronizationContext()  在UI线程中执行延续任务。