好吧,所以,我刚刚开始使用线程,现在需要花一点时间来理解这些概念,所以我写了一个非常简单的测试,看看如果更快,那么打印20000行会更快是(我认为它会更快,因为我有一个四核处理器?)
所以我先写了这个,(这就是我通常会做的事情):
System.DateTime startdate = DateTime.Now;
for (int i = 0; i < 10000; ++i)
{
Console.WriteLine("Producing " + i);
Console.WriteLine("\t\t\t\tConsuming " + i);
}
System.DateTime endtime = DateTime.Now;
Console.WriteLine(a.startdate.Second + ":" + a.startdate.Millisecond + " to " + endtime.Second + ":" + endtime.Millisecond);
然后使用线程:
public class Test
{
static ProducerConsumer queue;
public System.DateTime startdate = DateTime.Now;
static void Main()
{
queue = new ProducerConsumer();
new Thread(new ThreadStart(ConsumerJob)).Start();
for (int i = 0; i < 10000; i++)
{
Console.WriteLine("Producing {0}", i);
queue.Produce(i);
}
Test a = new Test();
}
static void ConsumerJob()
{
Test a = new Test();
for (int i = 0; i < 10000; i++)
{
object o = queue.Consume();
Console.WriteLine("\t\t\t\tConsuming {0}", o);
}
System.DateTime endtime = DateTime.Now;
Console.WriteLine(a.startdate.Second + ":" + a.startdate.Millisecond + " to " + endtime.Second + ":" + endtime.Millisecond);
}
}
public class ProducerConsumer
{
readonly object listLock = new object();
Queue queue = new Queue();
public void Produce(object o)
{
lock (listLock)
{
queue.Enqueue(o);
Monitor.Pulse(listLock);
}
}
public object Consume()
{
lock (listLock)
{
while (queue.Count == 0)
{
Monitor.Wait(listLock);
}
return queue.Dequeue();
}
}
}
现在,由于某种原因,我认为这会更快,但经过15次测试后,结果的中位数是......几毫秒不同,有利于非线程
然后我觉得嘿......也许我应该在一百万台Console.WriteLine上尝试它,但结果是相似的
我做错了什么?答案 0 :(得分:5)
写入控制台是内部同步的。它并不平行。它还会导致跨进程通信。
简而言之:这是我能想到的最糟糕的基准; - )
尝试对真实的东西进行基准测试,这是您真正希望加速的事情。它需要受CPU限制而不是内部同步。
答案 1 :(得分:3)
据我所知,你只有一个线程服务于队列,为什么这会更快?
答案 2 :(得分:2)
我有一个例子说明为什么你期望通过多线程获得大加速是错误的:
假设您要上传100张图片。单线程变量加载第一个,上传它,加载第二个,上传它等等。
此处的限制部分是您的互联网连接的带宽(假设每次上传都会占用您拥有的所有上传带宽)。
如果您创建100个线程仅上传1张图片,会发生什么?好吧,每个线程读取它的图片(这是加速一点点的部分,因为读取图片是并行而不是一个接一个地完成的。)
由于当前活动的线程使用100%的互联网上传带宽来上传其图片,因此当其他线程未激活时,没有其他线程可以上传单个字节。作为需要传输的字节数,100个线程需要每个上传一张图片的时间与一个线程需要一个接一个地上传100张图片的时间相同。
如果上传图片仅限于50%的可用带宽,您只能获得加速。然后,在50%的时间内完成100个线程,一个线程需要上传100张图片。
答案 3 :(得分:1)
“出于某种原因,我认为这会更快”
如果你不知道为什么你认为它会更快,为什么你会感到惊讶它不是?简单地启动新线程永远不能保证任何操作运行得更快。原始算法必须有一些低效率,新线程可以减少(这足以克服创建线程的额外开销)。
答案 4 :(得分:1)
其他人给出的所有建议都是很好的建议,特别是提到控制台是序列化的事实,以及添加线程不能保证加速的事实。
我想指出的是,其他人错过的是在原始场景中,您在主线程中打印所有内容,而在第二个场景中,您仅将整个打印任务委派给辅助线程工人即可。这不能比原来的情况更快,因为你只是将一个工人换成另一个。
您可能会看到加速的情况是这样的:
for(int i = 0; i < largeNumber; i++)
{
// embarrassingly parallel task that takes some time to process
}
然后将其替换为:
int i = 0;
Parallel.For(i, largeNumber,
o =>
{
// embarrassingly parallel task that takes some time to process
});
这将在工作者之间拆分循环,使每个工作者处理较小的原始数据块。如果任务不需要同步,您应该看到预期的加速。
答案 5 :(得分:0)
冷却测试。
处理线程时要记住的一件事是瓶颈。考虑一下:
你有一家餐馆。你的厨房每10个月就可以开一个新订单 分钟(你的厨师有膀胱问题,所以他总是在 卫生间,但是你女朋友的堂兄),所以他生产了6个订单 小时。
您目前只雇用一名服务员,可以参加餐桌 马上(他可能在E,但你不在乎,只要 服务很好)。
在商业的第一周,一切都很好:你得到 客户每十分钟一次。客户仍然等待十分之一 他们吃饭的时间,但没关系。
然而,在那一周之后,你每个人都会得到2个消费者 十分钟,他们必须等待多达20分钟才能得到他们的 膳食。他们开始抱怨和发出声音。上帝,你有 噪声。那你做什么?
服务员很便宜,所以你再雇两个。等待时间会改变吗? 一点也不......服务员会更快地得到订单(肯定会参加两个 客户并行),但仍有一些客户等待20分钟 厨师完成他们的订单。你需要另一位厨师,但是和你一样 搜索,你发现他们缺乏!他们每个人都在电视上 做一些疯狂的真人秀节目(除了你女朋友的堂兄谁 实际上,你发现,是一名前毒贩)。
在你的情况下,服务员是调用Console.WriteLine的线程;但是你的厨师就是控制台本身。它只能在一秒钟内拨打这么多电话。添加一些线程可能会使事情变得更快,但收益应该是最小的。
答案 6 :(得分:0)
您有多个来源,但只有1个输出。在这种情况下,多线程不会加快速度。这就像有一条道路,4车道合并成1车道。拥有4个车道可以更快地提高交通流量,但最终它会在合并为1车道时减速。