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

私が見る限り、キューにサービスを提供しているスレッドは1つしかないのに、なぜこれがもっと速いのでしょうか。

于 2012-04-04T14:36:10.377 に答える
2

I have an example for why your expectation of a big speedup through multi-threading is wrong:

Assume you want to upload 100 pictures. The single threaded variant loads the first, uploads it, loads the second, uploads it, etc.

The limiting part here is the bandwidth of your internet connection (assuming that every upload uses up all the upload bandwidth you have).

What happens if you create 100 threads to upload 1 picture only? Well, each thread reads its picture (this is the part that speeds things up a little, because reading the pictures is done in parallel instead of one after the other).

As the currently active thread uses 100% of the internet upload bandwidth to upload its picture, no other thread can upload a single byte when it is not active. As the amount of bytes that needs to be transmitted, the time that 100 threads need to upload one picture each is the same time that one thread needs to upload 100 pictures one after the other.

You only get a speedup if uploading pictures was limited to lets say 50% of the available bandwidth. Then, 100 threads would be done in 50% of the time it would take one thread to upload 100 pictures.

于 2012-04-04T14:45:29.877 に答える
1

「どういうわけか、これはもっと速いだろうと思った」

なぜもっと速くなると思ったのかわからないのに、なぜそうではないことに驚いたのですか?新しいスレッドを起動するだけでは、操作が高速になるとは限りません。元のアルゴリズムには、新しいスレッドが削減できる非効率性がいくらかある必要があります(これは、スレッドを作成するための余分なオーバーヘッドを克服するのに十分です)。

于 2012-04-04T14:35:15.480 に答える
1

他の人からのアドバイスはすべて良いアドバイスです。特に、コンソールがシリアル化されているという事実と、スレッドの追加がスピードアップを保証しないという事実についての言及です。

私が指摘したいことと、他の人が見逃しているように見えることは、元のシナリオではすべてをメインスレッドで印刷しているのに対し、2番目のシナリオでは印刷タスク全体をセカンダリワーカーに委任しているだけであるということです。あるワーカーを別のワーカーと交換しただけなので、これは元のシナリオよりも速くなることはありません。

スピードアップが見られるシナリオは次のとおりです。

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つは、ボトルネックです。このことを考慮:

あなたはレストランを持っています。あなたのキッチンは10分ごとに新しい注文をすることができます(あなたのシェフは膀胱の問題があるので彼はいつもバスルームにいますが、あなたのガールフレンドのいとこです)、それで彼は1時間に6つの注文を出します。

あなたは現在、すぐにテーブルに出席できるウェイターを1人だけ雇用しています(彼はおそらくEにいますが、サービスが良好である限り気にしません)。

ビジネスの最初の週はすべて問題ありません。10分ごとに顧客を獲得します。顧客はまだ食事を正確に10分間待ちますが、それは問題ありません。

ただし、その週以降は、10分ごとに2人もの衣装を着せるようになり、食事をとるには20分も待たなければなりません。彼らは不平を言い始め、音を立て始めます。そして、神よ、あなたには騒音があります。それで、あなたは何をしますか?

ウェイターは安いので、あと2人雇います。待ち時間は変わりますか?まったくそうではありません...ウェイターは確実に注文をより早く受け取ります(2人の顧客に並行して出席します)が、それでも一部の顧客はシェフが注文を完了するまで20分待ちます。別のシェフが必要ですが、検索すると、彼らが見つかります不足しています!彼ら全員がテレビでクレイジーなリアリティ番組をやっています(実際には、元ドラッグディーラーであるガールフレンドのいとこを除いて)。

あなたの場合、ウェイターはConsole.WriteLineを呼び出すスレッドです。しかし、あなたのシェフはコンソールそのものです。1秒間に多くの呼び出しを処理することしかできません。いくつかのスレッドを追加すると、処理が少し速くなる可能性がありますが、ゲインは最小限に抑える必要があります。

于 2012-04-04T14:56:28.707 に答える
0

複数のソースがありますが、出力は1つだけです。その場合、マルチスレッドはそれをスピードアップしません。これは、4車線が1車線に合流する道路があるようなものです。4車線になると交通は速く移動しますが、最終的に1車線に合流すると速度が低下します。

于 2012-04-04T15:30:46.870 に答える