【问题标题】:C# multiple background workers accessing an objectC# 多个后台工作人员访问一个对象
【发布时间】:2013-05-07 10:05:46
【问题描述】:

我有一个字符串列表,其中包含大约 20000 个字符串,每 1000 个字符长。我想使用多个后台工作人员将所有这些字符串替换为相同位置的相同字符串的反转版本。

这是我目前正在做的事情:

设置后台工作人员(8 个,因为计算机有 8 个核心)

 for (int j = 0; j < 8; j++)
    {
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += DoWork;
    worker.RunWorkerCompleted += WorkComplete;
    worker.RunWorkerAsync();
    }

我遇到的问题是我不知道在 doWork 函数中放什么。

dowork 函数是否应该像这样循环:

private void DoWork(object sender, DoWorkEventArgs e)
{
   while(list.count > 0)
   {
      reverse and add to list
   }         
}

还是应该 doWork 函数只做反转,然后将反转的字符串传递给 WorkComplete 函数?

private void DoWork(object sender, DoWorkEventArgs e)
    {
       reverse string
       r.result = reversed string 
    }

【问题讨论】:

  • 作为后台工作人员的替代方案,您是否查看过Task Parallel Librarymsdn.microsoft.com/en-us/library/dd460717.aspx
  • 您希望如何跟踪哪些列表项已被其他后台工作程序实例处理?
  • 这并不是后台工作人员 (BGW) 的设计目的。你通常有一个 BGW,它不使用共享数据(除了在进程和完成事件中)。如果您希望多个事物同时处理数据,我建议您使用 TPL 并启动一个任务。

标签: c# multithreading backgroundworker


【解决方案1】:

我只是想建议一种替代方法。

您可以只创建一个并在其 DoWork() 中使用 Parallel.ForEach() 来反转字符串,而不是创建多个 BackgroundWorker。

这样,它将为您优化处理线程数。

您仍然需要使用 BackgroundWorker 以避免锁定 UI 线程。

这是一个在控制台应用程序中运行的可编译示例:

using System;
using System.Linq;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            string[] data = Enumerable.Range(10000, 100).Select(i => i.ToString()).ToArray();

            Parallel.ForEach(data, (item, state, index) => data[index] = Reverse(item));

            foreach (var s in data)
                Console.WriteLine(s);
        }

        public static string Reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }
    }
}

此外,如果您使用的是 .Net 4.5,则可以通过使用新的 await/async 功能完全避免使用 BackgroundWorker。

例如,创建一个默认的 Windows 窗体应用程序并在其上放置一个名为 label1 的标签和一个名为 button1 的按钮。然后把Form1.cs文件改成:

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            data = Enumerable.Range(10000, 1000000).Select(i => i.ToString()).ToArray();
        }

        async void button1_Click(object sender, EventArgs e)
        {
            label1.Text = "Reversing strings...";
            await doWork();
            label1.Text = "Reversed strings.";
        }

        Task doWork()
        {
            return Task.Factory.StartNew(() => Parallel.ForEach(data, (item, state, index) => data[index] = reverse(item)));
        }

        static string reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }

        readonly string[] data;
    }
}

当您单击按钮时,用户界面将在字符串反转时保持响应。

【讨论】:

  • @686 我希望您可能需要阅读一些文档才能了解它是如何工作的......
  • 酷,这似乎是一个很好的解决方案。对不起,我不能投票,因为我还没有足够的代表。
【解决方案2】:

使用 BackgroundWorker 对您来说至关重要吗?使用 TPL 非常简单:

using System.Threading.Tasks;

Parallel.For(0, strings.Length, i=> strings[i] = reversed string);

TPL 将为您平衡负载(默认情况下,它使用您的 CPU 内核的可用数量),这也适用于具有不同内核数量的其他机器。

【讨论】:

  • 感谢您的回复,对我来说使用后台工作人员并不重要。我只想尽快完成任务。我试试看
猜你喜欢
  • 1970-01-01
  • 2019-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多