実際には、複数のスレッドでデータを変更するのは適切ではありません。結局のところ、redis サーバーはシングルスレッドであり、すべてのコマンドはシリアルに実行されます。それは、クライアントが送信したときのみです。一部のコマンド配置の問題やネットワーク時間の違いにより、データの不整合が発生します。この記事は数値の加算と減算に関するものですが、ロックの状況を説明するために、アトミック コマンド incr は意図的に使用されていません。 (推奨: redis ビデオ チュートリアル )
最初に、単純な RedisHelper、値の設定、値の取得、同時ロックの設定を追加します。これにより、後続の操作で正確に知ることができます。私がしたこと。
public class RedisHelper { public RedisClient client = new RedisClient("127.0.0.1", 6379); public void Set<T>(string key, T val) { client.Set(key, val); } public T Get<T>(string key) { var result = client.Get<T>(key); return result; } public IDisposable Acquire(string key) { return client.AcquireLock(key); } }
以下の同時実行コードを見ると、新しいスレッドが 2 つだけ追加されています。 2 つのスレッドが同じキーに同時にアクセスしようとしており、それぞれ 50,000 回アクセスします。同時条件では、データの正確性を保証するのは困難です。出力結果を比較してください。
static void Main(string[] args) { RedisHelper rds = new RedisHelper(); rds.Set<int>("mykey1", 0); Thread myThread1 = new Thread(AddVal); Thread myThread2 = new Thread(AddVal); myThread1.Start(); myThread2.Start(); Console.WriteLine("等待两个线程结束"); Console.ReadKey(); } public static void AddVal() { RedisHelper rds = new RedisHelper(); for (int i = 0; i < 50000; i++) { int result = rds.Get<int>("mykey1"); rds.Set<int>("mykey1", result + 1); } Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1")); }
はい、単一スレッドで 2 つの 50000 を実行すると、100000 が出力されます。現在、2 つの同時スレッドが同時に実行されていますが、同時実行性により、データ結果が期待どおりにならないことがよくあります。この問題を解決するには、Redis がすでに用意されています。
私の RedisHelper のメソッドの 1 つが public IDisposable Acquire(string key) であることがわかります。また、IDisposable が返されることもわかります。これは、リソースを手動で解放する必要があることを示しています。
メソッド内の AcquireLock が重要なポイントです。これは Redis でロックを要求するようなものです。ロックされたリソースには 1 つのスレッドのみがアクセスでき、2 つのスレッドによって同時に取得または設定されることはありませんこれら 2 つのスレッドは交互に実行する必要があります。もちろん、ここでの交互は、あなたに 1 回、私に 1 回という意味ではありません。また、あなたに複数回、私に 1 回ということもあります。以下のコードを参照してください。
static void Main(string[] args) { RedisHelper rds = new RedisHelper(); rds.Set<int>("mykey1", 0); Thread myThread1 = new Thread(AddVal); Thread myThread2 = new Thread(AddVal); myThread1.Start(); myThread2.Start(); Console.WriteLine("等待两个线程结束"); Console.ReadKey(); } public static void AddVal() { RedisHelper rds = new RedisHelper(); for (int i = 0; i < 50000; i++) { using (rds.Acquire("lock")) { int result = rds.Get<int>("mykey1"); rds.Set<int>("mykey1", result + 1); } } Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1")); }
を使用して Acquire メソッドを呼び出してロックを取得していることがわかります。
最終的な出力結果は 100000 で、これは私たちが望む正しい結果です。前の 8W は、2 つのスレッドのうち 1 つが最初に実行を終了したためです。
また、正式な使用プロセスでは、使用後に付与されたロックを削除し、expire を使用して有効期限を追加することをお勧めします。
プログラム実行中の予期しない終了を避けるため、ロックは常に存在し、ロックされたデータは今後更新または取得されない可能性があります。
プログラムの実行が開始されたときに、コンソールを閉じてプログラムを再実行し、redis-cli オペレーション コンソールでロックした値を取得すると、期限切れを設定しないようにすることもできます。永久に取得されます。
この Redis インスタンスに接続されているすべてのマシンは、指定された名前を同時に取得するロックを 1 つだけ持つことができます。
StackExchange.Redis の記述方法は次のとおりです
var info = "name-"+Environment.MachineName; //如果5秒不释放锁 自动释放。避免死锁 if (db.LockTake("name", info, TimeSpan.FromSeconds(5))) { try { } catch (Exception ex) { } finally { db.LockRelease("name", token); } }
その他の redis 知識については、redis データベース チュートリアル 列に注目してください。
以上がRedis lockの簡単アプリ紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。