通过多线程提高性能

发布于 2024-10-05 00:33:11 字数 868 浏览 8 评论 0原文

我现在正在尝试通过使其多线程来提高 winform 应用程序的性能。目前该类如下所示:

public class MainClass
{
   List<DataItem> data; //thousands of DataItem, but each is independent

   //and a lot of non-thread-safe variables here,variable1 variable2 ...

   public void Go()
   {
      data.ForEach(item => DealWithDataItem(item));
   }

   public void DealWithDataItem(DataItem item)
   {
      //costs really long time here
      Step1(item);
      Step2(item); //and a lot of StepN(item)
   }

   public void StepN(DataItem item)
   {
      //variable1 = blabla
      //variable2 = blabla ..etc
   }
}

我想为每个 DataItem 使用 ThreadPool。

data.ForEach(item => ThreadPool.QueueUserWorkItem( s => DealWithDataItem(item) ));

但这么多非线程安全变量!我无法在某些方法中声明它们,因为它在 StepN 方法之间共享。而且让它们全部都是线程安全的非常困难!我做错了什么吗?有什么好的解决办法吗?谢谢!

I'm now trying to improve a winform application's performance by make it multi-threaded. Currently the class looks like:

public class MainClass
{
   List<DataItem> data; //thousands of DataItem, but each is independent

   //and a lot of non-thread-safe variables here,variable1 variable2 ...

   public void Go()
   {
      data.ForEach(item => DealWithDataItem(item));
   }

   public void DealWithDataItem(DataItem item)
   {
      //costs really long time here
      Step1(item);
      Step2(item); //and a lot of StepN(item)
   }

   public void StepN(DataItem item)
   {
      //variable1 = blabla
      //variable2 = blabla ..etc
   }
}

I want to use ThreadPool for each DataItem.

data.ForEach(item => ThreadPool.QueueUserWorkItem( s => DealWithDataItem(item) ));

But so many non-thread-safe variables! I can't declare them in some method, because it's shared between StepN methods. And it's quite hard to make them all thread-safe! Am I doing anything wrong? Any good solutions? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

疑心病 2024-10-12 00:33:11

尝试使用 ParallelEnumerable.AsParallel

data.AsParallel.ForEach(DoWork);

它将根据处理器/内核的数量自动创建线程。
唯一的问题是它包含在 Framework 4.0 中。
有关 PLINQ 的详细信息。 (正如andras评论的那样:对于framwork 3.5,它可以作为独立的反应式扩展 (Rx))

UPD:正如 0xA3 所说,强烈建议重构代码,使每个项目都有自己的计算变量。
我建议你将计算逻辑提取到DataItem中

,或者创建像“Calculator”这样的特殊类,这将完成所有工作,因此DataItem只会存储数据,计算逻辑将包含在Calculator类中。

data.AsParallel.ForEach(x=> new Calculator().DoWork(x));

其中 Calculator 类是这样的

class Calculator
{
   // variables here

  void DoWork(DataItem item)
  {
     Step1(item);
     Step2(item);
     // ...
     // StepN(item);
  }
}

Try using ParallelEnumerable.AsParallel.

data.AsParallel.ForEach(DoWork);

It will automatically create threads depending on amount of processors / cores.
The only problem, that it's included in Framework 4.0.
More info about PLINQ. (And as andras commented: for framwork 3.5 it is available as stand-alone Reactive Extensions (Rx))

UPD: as 0xA3 said, refactoring code, making each item have it's own calc variables is strongly recommended.
I suggest you to extract calculation logics to DataItem

Or create special class like "Calculator", which would be do all the work, so DataItem would only store data, and logics of calculations would be contained in Calculator class.

data.AsParallel.ForEach(x=> new Calculator().DoWork(x));

where Calculator class is something like this

class Calculator
{
   // variables here

  void DoWork(DataItem item)
  {
     Step1(item);
     Step2(item);
     // ...
     // StepN(item);
  }
}
遮云壑 2024-10-12 00:33:11

最好的方法可能是重构代码,以便摆脱不同数据项之间共享的所有字段。

更改(或子类化)DataItem 类以包含用于操作 dataItem 的所有相关数据和方法,以便您的代码更改为如下所示:

public void DealWithDataItem(DataItem item)
{
    item.Step1(); // does not change the state of `this` 
                  // and only changes variables that are private to `item`
    item.Step2(); // and a lot of StepN(item)
}

Probably the best way would be to refactor your code, so that you get rid of all that fields shared between the different data items.

Change (or subclass) the DataItem class to contain all the relevant data and methods for manipulating a dataItem, so that your code changes to something like this:

public void DealWithDataItem(DataItem item)
{
    item.Step1(); // does not change the state of `this` 
                  // and only changes variables that are private to `item`
    item.Step2(); // and a lot of StepN(item)
}
等待我真够勒 2024-10-12 00:33:11

由于每个 DataItem 都是独立的,因此将工作移至新的 DataItem 工作方法中,并让每个实例自行处理:

public class MainClass
{
    List<DataItem> data; //thousands of DataItem, but each is independent

    public void Go()
    {
        data.ForEach(item => ThreadPool.QueueUserWorkItem(s => s.DealWithSelf()));
    }
}

public class DataItem
{
    //and a lot of non-thread-safe variables here,variable1 variable2 ...

    void DealWithSelf()
    {
        //costs really long time here
        Step1(item);
        Step2(item); //and a lot of StepN(item)
    }

    public void StepN(DataItem item)
    {
        //variable1 = blabla
        //variable2 = blabla ..etc
    }
}

Since each DataItem is independent, move the work into a new DataItem worker method, and let each instance deal with itself:

public class MainClass
{
    List<DataItem> data; //thousands of DataItem, but each is independent

    public void Go()
    {
        data.ForEach(item => ThreadPool.QueueUserWorkItem(s => s.DealWithSelf()));
    }
}

public class DataItem
{
    //and a lot of non-thread-safe variables here,variable1 variable2 ...

    void DealWithSelf()
    {
        //costs really long time here
        Step1(item);
        Step2(item); //and a lot of StepN(item)
    }

    public void StepN(DataItem item)
    {
        //variable1 = blabla
        //variable2 = blabla ..etc
    }
}
℡寂寞咖啡 2024-10-12 00:33:11

MainClass 在你的 GUI 线程中吗?您不应该在 GUI 线程中进行任何数据处理;在单独的线程中运行MainClass

如何做到这一点?这完全取决于您未向我们展示的 blabla 内容。 MainClass 需要返回结果吗?使用BeginInvoke/EndInvoke。您需要更新 GUI 吗?使用BackgroundWorker。如果您想要更好的答案,您必须向我们提供更多信息。

Is MainClass in your GUI thread? You should not be doing any data processing in your GUI thread; run MainClass in a separate thread.

How to do this? That depends entirely on the blabla stuff you have not shown us. Does MainClass need to return a result? Use BeginInvoke/EndInvoke. Do you need to update the GUI? Use BackgroundWorker. If you want a better answer you will have to give us more information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文