1

好的,所以,我刚开始搞线程,现在需要一些时间来理解这些概念,所以我写了一个非常简单的测试,看看如果打印出 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 上试试,但结果是相似的

难道我做错了什么 ?

4

7 回答 7

5

写入控制台是内部同步的。它不是平行的。它还会导致跨进程通信。

简而言之:这是我能想到的最糟糕的基准;-)

尝试对一些真实的东西进行基准测试,你实际上想要加速的东西。它需要受 CPU 限制而不是内部同步。

于 2012-04-04T14:43:10.917 回答
3

据我所知,您只有一个线程服务于队列,那为什么会更快呢?

于 2012-04-04T14:36:10.377 回答
2

我有一个例子说明为什么您对通过多线程实现大幅加速的期望是错误的:

假设您要上传 100 张图片。单线程变体加载第一个,上传,加载第二个,上传等等。

这里的限制部分是您的 Internet 连接的带宽(假设每次上传都会用完您拥有的所有上传带宽)。

如果您创建 100 个线程来仅上传 1 张图片会怎样?好吧,每个线程都读取它的图片(这是加快速度的部分,因为读取图片是并行完成的,而不是一个接一个)。

由于当前活动线程使用 100% 的互联网上传带宽来上传其图片,因此其他线程在不活动时无法上传单个字节。作为需要传输的字节数,100个线程每个需要上传一张图片的时间与一个线程需要依次上传100张图片的时间相同。

如果上传图片被限制为可用带宽的 50%,您只会获得加速。然后,100 个线程将在 50% 的时间内完成,一个线程需要上传 100 张图片。

于 2012-04-04T14:45:29.877 回答
1

“出于某种原因,我认为这会更快”

如果你不知道为什么你认为它会更快,为什么你会惊讶它不是?永远不能保证简单地启动新线程会使任何操作运行得更快。新线程可以减少原始算法中的一些低效率(这足以克服创建线程的额外开销)。

于 2012-04-04T14:35:15.480 回答
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
    });

这将在工作人员之间拆分循环,以便每个工作人员处理较小的原始数据块。如果任务不需要同步,您应该会看到预期的加速。

于 2012-04-04T15:24:00.977 回答
0

您有多个来源,但只有 1 个输出。在这种情况下,多线程不会加快速度。这就像有一条道路,其中 4 条车道合并为 1 条车道。拥有 4 条车道会使交通更快,但最终当它合并到 1 条车道时会减慢速度。

于 2012-04-04T15:30:46.870 回答
0

酷测试。

处理线程时要记住的一件事是瓶颈。考虑一下:

你有一家餐厅。你的厨房可以每 10 分钟下一个新订单(你的厨师有膀胱问题,所以他总是在浴室里,但他是你女朋友的表弟),所以他每小时生产 6 个订单。

您目前只雇用一名服务员,可以立即上桌(他可能在 E 上,但只要服务好,您就不会在意)。

在营业的第一周,一切都很好:你每十分钟就有一次客户。顾客仍然要等十分钟才能用餐,但这没关系。

然而,在那一周之后,你每十分钟就有多达 2 位顾客,他们必须等待多达 20 分钟才能得到他们的饭菜。他们开始抱怨和制造噪音。上帝,你有噪音。所以你会怎么做?

服务员很便宜,所以你再雇两个。等待时间会改变吗?一点也不...服务员会更快地得到订单,当然(同时接待两个顾客),但仍有一些顾客等待 20 分钟让厨师完成他们的订单。你需要另一个厨师,但当你搜索时,你会发现他们缺乏!他们每个人都在电视上做一些疯狂的真人秀(除了你女朋友的表弟,你发现他实际上是一名前毒贩)。

在您的情况下,服务员是调用 Console.WriteLine 的线程;但是您的厨师就是控制台本身。它每秒只能处理这么多的呼叫。添加一些线程可能会使事情变得更快,但收益应该很小。

于 2012-04-04T14:56:28.707 回答