如何在同一列表视图框中为不同的列表视图值运行两个进程?

时间:2016-11-02 14:53:13

标签: c# winforms parallel-processing

我正在开发一个更大的程序,但它对列表框中的每个值所做的操作需要很长时间。我想通过在同一个listviewbox中为多个值执行相同的过程来加快速度,基本上尝试添加某种类型的并行操作逻辑来完成工作。

我创建了一个快速程序,这是我工作的更大程序的一个非常简单的版本,我希望有人可以建设性地指出我正确的方向。

有没有一种方法可以列出一个listviewbox,我可以同时从列表的顶部和底部开始,让每个人都按照自己的方式工作直到他们在中间相遇?我不能用另一种方式来解决这个问题。

以下是我现在正在与后台工作人员进行的“代码”示例,没什么好看的(再次,这是一个模拟程序,因为我正在处理的实际程序的“复杂性”。)

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {

        ListViewItem lst = listView1.SelectedItems[0];

        foreach (ListViewItem user in listView1.Items)
        {
            MessageBox.Show(user.SubItems[0].Text);
        }

    }

    private void button1_Click(object sender, EventArgs e)
    {
        CheckForIllegalCrossThreadCalls = false; // I know, but this is an example program, so I'm using this for ny own sanity sake right now.
        backgroundWorker1.RunWorkerAsync();
    }

这是程序的GUI部分

enter image description here

我希望这是有道理的。如果没有,我可以进一步阐述,但这是我要做的事情的要点。

(我已经尝试过查看类似问题的堆栈溢出,但是我没有找到帮助我,因为他们要么使用不同的语言,要么是他们不能遵循的切线,因为它超出了范围我的程序,我不明白如何调整他们的答案我的程序。)

更新W / ANSWER

如果这对将来有所帮助,我会在评论中提出建议并在我的代码中实施Parallel.ForEach。因为这是一个列表视图,我的方法必须更有创意。

我的ForEach语句现在看起来像这样:

var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.50) * 1.0)) };

Parallel.ForEach<ListViewItem>(lstBackupUsers.Items.Cast<ListViewItem>(),opts, name => { // Long stuff to do here });

基本上,我在backgroundworker任务中删除了常规的“foreach”命令,并将其替换为上面的Parallel.ForEach。作为参考,我不得不使用ParallelOptions来限制资源量(在这种情况下,我的资源的50%。)

更新2(奇怪的问题)

所以上面的语句按预期工作,并且运行良好,除了Parallel.ForEach(...)语句在使用 MaxDegreeOfParallelism参数时,不会通过我的整个列表框重复。如果我不在ForEach语句中使用它,那么我会收到“Out of memory”异常,但是如果我使用它,那么我的ForEach会运行几行然后就会停止。

就像这样(对我而言):

如果我设置MaxDegreeOfParallelism,它只会通过我的机器中的核心数量与listview框重复(无论我告诉MaxDegreeOfParallelism使用什么值。)例如:

我有一个包含20行的listview框,我的计算机只重复了8行,然后ForEach停止了(我的机器现在有8个核心。)

关于我还能做什么的任何想法?

谢谢!

更新3

我现在有var result = Parallel.ForEach而我正在检查result.IsCompleted,这有助于我指出正确的方向来解决循环问题。

1 个答案:

答案 0 :(得分:1)

此任务不需要Background-Worker。正如评论中提到的gilmishal,您可以使用Parallel.Foreach。此类位于任务名称空间内,该名称空间包含Microsoft的新异步TAP模式。如果使用多线程,则应该查看此命名空间。 Parallel.Foreach在一个新线程中启动你在方法体内的操作(​​如果这是有意义的)。所以你不需要从顶部和底部开始。几乎在同一时间(并行)为列表中的每个元素开始循环。

Parallel.ForEach(username, row => { // do your long running stuff });

<强> UDPATE:

默认情况下,并没有在额外的Thread中执行Parallel.ForEach。用户界面可以冻结。为避免此行为,您应该在额外的任务中运行Parallel.ForEach。这个article指出了为什么你不应该在UI线程中运行Parallel.ForEeach。因此,对于停止冻结UI,请执行以下操作:

 private void button1_Click(object sender, EventArgs e)
 {
    Task.Factory.StartNew(() => {
        Parallel.ForEach(username, row => { // background_dowork stuff here? });    
    });
 }

确保您不访问分离线程中的任何UI组件。