Tatsächlich ist es nicht angebracht, Daten mit mehreren Threads zu ändern. Schließlich ist der Redis-Server Single-Threaded und alle Befehle werden seriell ausgeführt Befehle gleichzeitig ausführen, was zu einer Serialisierung führt. Einige Probleme mit der Befehlsanordnung und Netzwerkzeitunterschiede führen zu Dateninkonsistenzen. Obwohl es in diesem Artikel um die Addition und Subtraktion von Zahlen geht, wird zur Veranschaulichung der Sperrsituation der atomare Befehl incr nicht absichtlich verwendet. (Empfohlen: Redis-Video-Tutorial)
Fügen Sie zunächst einen einfachen RedisHelper, einen Set-Wert, einen Get-Wert und eine Set-Parallelitätssperre hinzu, damit Sie es in meinen nachfolgenden Vorgängen wissen genau das, was ich getan habe.
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); } }
Sehen Sie sich den gleichzeitigen Code unten an. Ich habe nur zwei neue Threads erstellt. Zwei Threads möchten gleichzeitig auf denselben Schlüssel zugreifen, und zwar jeweils 50.000 Mal. Unter gleichzeitigen Bedingungen ist es für uns schwierig, die Genauigkeit der Daten sicherzustellen. Bitte vergleichen Sie die Ausgabeergebnisse.
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")); }
Ja, mit unserem einzelnen Thread werden beim Ausführen von zwei 50000 100000 ausgegeben. Jetzt werden zwei gleichzeitige Threads gleichzeitig ausgeführt. Aufgrund der Parallelität entsprechen die Datenergebnisse häufig nicht unseren Wünschen. Um dieses Problem zu lösen, ist Redis bereits für uns bereit!
Sie können sehen, dass eine Methode in meinem RedisHelper public IDisposable Acquire(string key) ist. Sie können auch sehen, dass IDisposable zurückgegeben wird, was beweist, dass wir Ressourcen manuell freigeben müssen.
Der AcquireLock innerhalb der Methode ist der entscheidende Punkt. Es ist, als würde man in Redis nach einer Sperre fragen. Auf die gesperrte Ressource kann nur ein einzelner Thread zugreifen und sie wird nicht von zwei Threads gleichzeitig abgerufen oder festgelegt Diese beiden Threads müssen natürlich abwechselnd ausgeführt werden. Dies gilt nicht für einmal für Sie und einmal für mich. Siehe den Code unten.
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")); }
Sie können sehen, dass ich meine Acquire-Methode aufgerufen habe, um die Sperre zu erhalten.
Das endgültige Ausgabeergebnis ist 100000, was das richtige Ergebnis ist, das wir wollen. Die vorherige 8W+ liegt daran, dass einer der beiden Threads die Ausführung zuerst beendet hat.
Außerdem wird empfohlen, während des offiziellen Nutzungsprozesses die uns nach der Nutzung gegebene Sperre zu löschen und mithilfe von „expire“ eine Ablaufzeit hinzuzufügen.
Um ein unerwartetes Beenden während der Programmausführung zu vermeiden, bleibt die Sperre immer bestehen und die gesperrten Daten werden möglicherweise in Zukunft nicht aktualisiert oder abgerufen.
Sie können auch versuchen, den Ablauf nicht festzulegen. Wenn das Programm gerade mit der Ausführung beginnt, schließen Sie die Konsole, führen Sie das Programm erneut aus und rufen Sie den Wert ab, den Sie in der Redis-CLI-Bedienkonsole gesperrt haben Für immer erhalten.
Alle mit dieser Redis-Instanz verbundenen Maschinen können nur eine Sperre haben, die gleichzeitig den angegebenen Namen erhält
Im Folgenden wird beschrieben, wie StackExchange.Redis geschrieben wird
var info = "name-"+Environment.MachineName; //如果5秒不释放锁 自动释放。避免死锁 if (db.LockTake("name", info, TimeSpan.FromSeconds(5))) { try { } catch (Exception ex) { } finally { db.LockRelease("name", token); } }
Weitere Informationen zu Redis finden Sie in der Spalte Redis-Datenbank-Tutorial.
Das obige ist der detaillierte Inhalt vonEinfache Anwendungseinführung der Redis-Sperre. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!