开发者

Improve the performance by multi-threading

开发者 https://www.devze.com 2023-01-28 20:16 出处:网络
I\'m now trying to improve a winform application\'s performance by make it multi-threaded. Currently the class looks like:

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!


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);
  }
}


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)
}


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
    }
}


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号