我现在正试图通过使其成为多线程来改进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
方法之间共享。并且很难让它们都是线程安全的!我做错了吗?好的解决方案?谢谢!
答案 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
。如果您想要更好的答案,您必须向我们提供更多信息。