多线程并没有改善性能,但使其更慢
我有一个多线程应用程序,比较两个List o1和o2中的CompareRow,并获得相似度,然后在列表中存储o1.CompareRow,o2.CompareRow和Similarity ,因为getSimilarity过程非常耗时,而且数据通常超过1000,所以使用多线程应该帮助,但事实上,它不是,请 帮助指出的是,几件事情我已经考虑的是多线程并没有改善性能,但使其更慢
1. Database shouldnot be a problem, cause i already load the data into
two List<>
2. There is no shared writable data to complete
3. the order of the records is not a problem
请求帮助,这是紧急的,截止日期是接近的....
public class OriginalRecord
{
public int PrimaryKey;
public string CompareRow;
}
===============================================
public class Record
{
// public ManualResetEvent _doneEvent;
public string r1 { get; set; }
public string r2 { get; set; }
public float similarity { get; set; }
public CountdownEvent CountDown;
public Record(string r1, string r2, ref CountdownEvent _countdown)
{
this.r1 = r1;
this.r2 = r2;
//similarity = GetSimilarity(r1, r2);
CountDown = _countdown;
}
public void ThreadPoolCallback(Object threadContext)
{
int threadIndex = (int)threadContext;
similarity = GetSimilarity(r1, r2);
CountDown.Signal();
}
private float GetSimilarity(object obj1, object obj2)
{
//Very time-consuming
ComparisionLibrary.MatchsMaker match
= new ComparisionLibrary.MatchsMaker (obj1.ToString(), obj2.ToString());
return match.Score;
}
}
================================================================
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
List<OriginalRecord> oList1=... //get loaded from database
List<OriginalRecord> oList2 =... //get loaded from database
int recordNum = oList1.Count * oList2.Count;
CountdownEvent _countdown = new CountdownEvent(recordNum);
Record[] rArray = new Record[recordNum];
int num = 0;
for (int i = 0; i <oList1.Count; i++)
{
for (int j = 0; j < oList2.Count; j++)
{
//Create a record instance
Record r
=new Record(oList1[i].CompareRow,oList2[j].CompareRow,ref _countdown);
rArray[num]=r;
//here use threadpool
ThreadPool.QueueUserWorkItem(r.ThreadPoolCallback, num);
num++;
}
}
_countdown.Wait();
List<Record> rList = rArray.ToList();
PopulateGridView(rList);
}
这里是我在调试模式下拍摄的照片 引起我注意的两件事是 1.只有4个线程创建工作,但我设置线程池中的minthreads是10 2.正如你所看到的,甚至4个线程创建的,但只有一个线程在任何时间工作, 更糟糕的是,有时没有线程是由方式工作 ,该ComparisionLibrary是我下载做繁重的工作
我不能交库照片,你会请给我一封电子邮件或者我可以把照片发给你,谢谢。
嗨,我的假设:
1)如果您的计算机有1个CPU比你不会获得任何性能改进。事实上,由于Context Switch,你会失去表现。
2)尝试设置ThreadPool类的最大线程值。
ThreadPool.SetMaxThreads(x);
3)尝试使用PLINQ。
我的CPU是四核的,我把线程设置为100,并且我可以看到超过100个线程在运行,并且CPU使用率接近80%到90%,但仍然使用比单线程更多的时间,所以很伤心~~~ – 2012-03-21 07:59:33
其实,我想过之前的上下文切换,但没有证明这是问题,此外,上下文切换似乎可以避免,没有我可以做... – 2012-03-21 08:02:56
这样的猜测,尝试使用TPL
,而不是简单的线程池,如:
int nums = new int[1];
nums[0] = num;
Task t = null;
t = new Task(() =>
{
r.ThreadPoolCallback(nums[0]);
});
t.Start();
编辑 你试图比较:
通过这样的事情更换
ThreadPool.QueueUserWorkItem(r.ThreadPoolCallback, num);
两个list1,list2,每个项目都在独立的线程池中,这就是list1.Count*list2.Count
线程池的调用,这个我觉得很喜欢平顺化(这可能会导致许多上下文切换)。
尝试将所有比较任务分成几个组(例如4-8),并在单独的线程中启动每个比较任务。也许这可能有帮助。但是,这只是一个假设。
对不起,只是试过,没有运气,没有任何区别,但谢谢反正 – 2012-03-21 08:14:18
我在想,如果上下文切换是问题,如果我使用控制台而不是窗口形式,会有帮助吗? – 2012-03-21 08:21:25
它不会帮助,我认为 – 2012-03-21 09:11:27
如果您想将大任务分解为几个小任务,请注意,只有小任务在运行时间方面不会太短,并行化才有效。如果您将2秒的运行时作业减少到100.000 0.02毫秒的作业,那么将作业分配给工作人员的开销会非常大,以至于平行过程的运行速度会非常慢,那么通常会这样做。只有并行化开销远小于其中一个小任务的平均运行时间时,您才会看到性能提升。尽量减少大块的问题。
另请参阅http://stackoverflow.com/questions/9808495/multicore-with-plyr-mc的一些信息,虽然在不使用C# – 2012-03-21 16:49:04
我认为这是建议使用PLINQ http://msdn.microsoft.com/en-us/library/dd997425.aspx而不是线程池。你可以轻松地做到这一点。 – 2012-03-21 07:43:39
我试过了,但并不是真的平行。ForEach(oList1,(o1,state,i)=> {Parallel.ForEach(oList2,(o2,state1,i1)=> {记录r =新记录(o1.CompareRow,o2.CompareRow); rList.Add(r );});}); rList是concurrentBag – 2012-03-21 07:48:53
我也推荐使用plinq(parallel for)。另外你应该注意的是,如果你的处理器没有足够的物理内核(超线程并不总是像广告所说的那样工作),那么在多线程中运行一个程序实际上会减慢一切。 – linkerro 2012-03-21 07:56:42