通过多线程提高性能

时间:2010-12-01 11:16:10

标签: c# .net multithreading thread-safety threadpool

我现在正试图通过使其成为多线程来改进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方法之间共享。并且很难让它们都是线程安全的!我做错了吗?好的解决方案?谢谢!

4 个答案:

答案 0 :(得分:3)

尝试使用ParallelEnumerable.AsParallel

data.AsParallel.ForEach(DoWork);

它将根据处理器/内核的数量自动创建线程。 唯一的问题是,它包含在Framework 4.0中。 有关PLINQ的更多信息。 (并且 andras 评论说:对于framwork 3.5,它可以作为独立的Reactive Extensions (Rx)使用)

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

或创建像“计算器”这样的特殊类,这将完成所有工作,因此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);
  }
}

答案 1 :(得分:0)

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

更改(或子类)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)
}

答案 2 :(得分:0)

由于每个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
    }
}

答案 3 :(得分:0)

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

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