0

我有这样的功能:

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 次,然后合并结果或使用线程安全列表或字典。

我的问题是,我怎样才能在 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");
}

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

如何管理超过 1 个线程来运行相同的功能,同时又能够知道每个线程何时结束关闭或保存或合并数据或执行我在主线程中剩下的任何事情?

4

3 回答 3

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();
    }
}
于 2012-05-27T04:47:20.650 回答
1

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

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

编辑在我的评论中,我建议使用以下代码。

在OP的评论中,我看到

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

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

  1. 要求 N 页
  2. 当任何一页可用时,使用结果
  3. 当所有 N 个页面都可用并被使用时,整理该结果

这需要异步编程。在 .NET 4.0 中,它主要在 F# 2.0 下可用。C# 4.0 可以使用带有延续的 APM,但我不推荐它。

C# vNext 对此提供支持,请参阅 VS 2012。

于 2012-05-27T04:35:18.640 回答
0

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

    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 线程中执行延续任务。

于 2012-05-27T09:36:49.200 回答