lock



from https://www.cnblogs.com/wolf-sun/p/4209521.html


最常使用的锁是如下格式的代码段:
private static object objlock = new object();
lock (objlock )
{
    //要执行的代码逻辑
}
1、lock的是引用类型的对象,string类型除外。
2、lock推荐的做法是使用静态的、只读的、私有的对象。
3、保证lock的对象在外部无法修改才有意义,如果lock的对象在外部改变了,对其他线程就会畅通无阻,失去了lock的意义。



from https://qiita.com/tadokoro/items/28b3623a5ec58517d431


マルチスレッドで高速な実装を行うにはロックを避けては通れません。
この記事では色々なC#を使ってロック方法の紹介とベンチマーク結果をご紹介します。

ロック方法によるパフォーマンス差1

ロック方法4スレッド32スレッド
unsafe211,494,252 / 秒6,578,947 / 秒
Interlocked6,896,551 / 秒3,215,434 / 秒
lock4,000,000 / 秒877,192 / 秒
SemaphoreSlim1,104,972 / 秒104,602 / 秒
Semaphore319,284 / 秒48,035 / 秒
Mutex234,962 / 秒37,199 / 秒
unsafeはロックを取得していないのでプログラマーの意図した動きにはなりませんが、ロックによるオーバーヘッドを見るために計測しました。
Interlocked > lock > SemaphoreSlim > Semaphore の順に早いようです。
とはいえロック方法によっては得手不得手があるので、使う状況をそれぞれ見ていきます。

Interlocked

int incrementedValue = Interlocked.Increment(ref intValue); // 安全にインクリメント
こんな感じで使います。
数値を単品で操作するケースはこれで十分でしょう。

lock

class X {
    object lockObject = new object();
    public void Work() {
        lock(lockObject) {
            // ロックの中
        }
    }
}
こんな感じです。
同じ引数のlock(){ ... }で囲った範囲同士であれば、シングルスレッドと同じ感覚で使えます。

SemaphoreSlim

class X {
    SemaphoreSlim sem = new SemaphoreSlim(1, 1);
    public async Task Work() {
        await sem.WaitAsync().ConfigureAwait(false);
        try {
            // ロックの中、awaitもok
        } finally {
            sem.Release();
        }
    }
}
lock方式だとロック中にawaitが使えないのですが3、こちらは使えます。
lock方式が使えるならそちらを、awaitを使うならこちらを選ぶと良さそうです。

Semaphore

class X {
    Semaphore sem = new Semaphore(1, 1);
    public void Work() {
        sem.WaitOne();
        try {
            // ロックの中、awaitもok
        } finally {
            sem.Release();
        }
    }
}
Semaphore方式はSemaphoreSlim方式と似てますが、awaitに対応していません。
速度ではlock方式に劣ります。
今回のベンチマークではこれを使うメリットは見い出せませんでした(^^;)
MSDNのSemaphoreSlimには以下の記載がありますので、Semaphoreは過去のものかもしれません(間違ってたらごめんなさい)。
名前付きセマフォとしてプロセス間でリソースをロックする場面でだけ使うと良いかもしれません。4
SemaphoreSlim クラス
リソースまたはリソースのプールに同時にアクセスできるスレッドの数を制限する Semaphore の軽量版を表します。

Mutex

class X {
    Mutex mut = new Mutex();
    public void Work() {
        mut.WaitOne();
        try {
            // ロックの中
        } finally {
            mut.ReleaseMutex();
        }
    }
}
使い方はSemaphoreとよく似ていて、こちらも名前付きにすると他プロセスからも見えるそうです。Semaphoreのように同時実行エントリ数を変更できない(1固定)のに、なぜかSemaphoreより性能が劣ります。

まとめと感想

Interlocked < lock < SemaphoreSlim < Semaphore < Mutex の順で高速。
特にスレッド数が増えると差も広がる傾向があります。


留言

熱門文章