3

これは奇妙なLinuxの癖かもしれませんが、私は非常に奇妙な振る舞いを観察しています。

次のコードは、同期されたバージョンの合計数を非同期バージョンと比較する必要があります。プログラムをシングルスレッド(1つのコアのみが使用されている)として観察しながら、パフォーマンスの向上が見られます(キャッシュではなく、コードを2つの別々のプログラムに分割した場合でも発生します)。

straceいくつかのスレッドアクティビティを表示しますが、topクローンなどの監視ツールは、使用されているコアを1つだけ表示します。

私が観察している2番目の問題は、スポーン率を上げると、メモリ使用量が爆発することです。スレッドのメモリオーバーヘッドはどれくらいですか?5000スレッドでは、最大10GBのメモリ使用量が得られます。

#include <iostream>
#include <random>
#include <chrono>
#include <future>
using namespace std;


long long sum2(const vector<int>& v, size_t from, size_t to)
{
    const size_t boundary = 5*1000*1000;

    if (to-from <= boundary)
    {
        long long rsum = 0;
        for (;from < to; from++)
        {
            rsum += v[from];
        }
        return rsum;
    }
    else
    {
        size_t mid = from + (to-from)/2;
        auto s2 = async(launch::async,sum2,cref(v),mid,to);

        long long rsum = sum2(v,from,mid);
        rsum += s2.get();
        return rsum;
    }
}

long long sum2(const vector<int>& v)
{
    return sum2(v,0,v.size());
}

long long sum(const vector<int>& v)
{
    long long rsum = 0;
    for (auto i : v)
    {
        rsum += i;
    }

    return rsum;
}

int main()
{
    const size_t vsize = 100*1000*1000;

    vector<int> x;
    x.reserve(vsize);

    mt19937 rng;
    rng.seed(chrono::system_clock::to_time_t(chrono::system_clock::now()));

    uniform_int_distribution<uint32_t> dist(0,10);

    for (auto i = 0; i < vsize; i++)
    {
        x.push_back(dist(rng));
    }

    auto start = chrono::high_resolution_clock::now();
    long long suma = sum(x);
    auto end = chrono::high_resolution_clock::now();

    cout << "Sum is " << suma << endl;
    cout << "Duration " << chrono::duration_cast<chrono::nanoseconds>(end - start).count() << " nanoseconds." << endl;

    start = chrono::high_resolution_clock::now();
    suma = sum2(x);
    end = chrono::high_resolution_clock::now();

    cout << "Async sum is " << suma << endl;
    cout << "Async duration " << chrono::duration_cast<chrono::nanoseconds>(end - start).count() << " nanoseconds." << endl;

    return 0;
}
4

2 に答える 2

1

同時に作業を行うスレッド間のオーバーラップが短すぎて目立たないため、1つのコアが使用されているのを観察するかもしれません。最新のハードウェアでは、メモリの連続領域から5mlnの値を合計するのは非常に高速であるため、親が合計を完了するまでに、子はほとんど開始されておらず、親はほとんどまたはすべての時間を子からの結果を待つことに費やしている可能性があります。オーバーラップが目立つようになるかどうかを確認するために、作業単位を増やしてみましたか?

パフォーマンスの向上について:ワークユニットが小さすぎるためにスレッド間にオーバーラップがない場合でも、マルチスレッドバージョンは追加のL1キャッシュメモリの恩恵を受けることができます。このようなテストでは、メモリがボトルネックになる可能性があり、シーケンシャルバージョンは1つのL1キャッシュのみを使用しますが、マルチスレッドバージョンはコアと同じ数を使用します。

于 2012-10-14T22:25:59.743 に答える
1

印刷されている時間を確認しましたか?私のマシンでは、シリアル時間は-O2で1秒未満ですが、パラレル合計時間は数倍高速です。したがって、CPU使用率は、「トップ」などが登録するのに十分な長さではない可能性があります。これは、通常、CPU使用率が1秒に1回しか更新されないためです。

スレッドあたりのカウントを減らしてスレッド数を増やすと、スレッド管理のオーバーヘッドが効果的に増加します。5000スレッドがアクティブな場合、タスクは追加のメモリで5000*min-thread-stack-sizeを使用します。私のマシンでは20Gbです!

ソースコンテナのサイズを大きくしてみませんか?並列セクションに十分な時間をかけると、対応する並列CPUの使用状況が表示されます。ただし、準備してください。整数の合計は高速であり、乱数の生成にかかる時間は、数値を合計する時間よりも1桁または2桁長くなる可能性があります。

于 2012-10-15T07:33:00.447 に答える