2016-04-14 14 views
3

Ich brauche eine Mutex-Methode in PHP, so dass es Exklusivität durch einen Variablenwert hält. Dies bedeutet, dass Threads mit demselben Wert nacheinander in diese Methode eingegeben werden sollen, während Threads mit unterschiedlichen Werten willkürlich auf diese Methode zugreifen können.Wie erstelle ich eine Mutex-Methode in PHP pro Variablenwert

Zum Beispiel, da Methode:

/** 
* @param integer $value 
*/ 
function mutexMethod($value) 
{ 
    // Lock for value $value 
    echo 'processing'; 
    sleep(2); 
    echo 'this is so heavy'; 
    // Unlock for value $value 
} 

Zum Beispiel (Ich brauche dies durch Apache ausgeführt werden):

time | 
0 | php > mutexMethod(1); | php > mutexMethod(2); | php > mutexMethod(1); 
1 | processing   | processing   | 
2 |      |      | 
3 | this is so heavy  | this is so heavy  | processing 
4 |      |      | 
5 |      |      | this is so heavy 

Als erste Lösung, die ich habe versucht mit semaphores aber Da $value einen beliebigen Wert erhalten kann, habe ich den Platz für Semaphoren sehr schnell verloren (Ich habe versucht, die Semaphore nach der Verwendung zu entfernen, aber das bricht andere Threads, die darauf warten, und da ich nicht wissen kann, ob Threads auf sie warten, Ich kann sie nicht willkürlich entfernen ily.

Als zweite Lösung habe ich versucht, eine Datei mit dem Wert $value als Name zu erstellen und flock zu verwenden, um jeden anderen Thread zu sperren. Obwohl dies im CLI funktioniert hat, konnte ich es nicht durch Apache schaffen. Es hat die Datei sicher gesperrt, aber es hat diese Sperre nie freigegeben, so dass jede andere Anfrage blockiert wurde, bis die erste Zeit abgelaufen ist (nach 30 Sekunden).

Endlich habe ich über die Verwendung von MySQL-Sperren, aber ich möchte sie so sehr vermeiden, wie wir die MySQL-Instanz für solche Dinge nicht verwenden möchten. Idealerweise möchten wir eine reine PHP-Lösung.

Haben Sie eine Idee, wie ich dieses Problem lösen kann? Ich würde gerne Single-Semaphore-Lösungen vermeiden (wie zum Beispiel einen einzigen Semaphor, um den Zugriff auf eine Datei zu kontrollieren, wo die Locks zu verfolgen sind), da dies einen massiven Flaschenhals erzeugen würde (speziell für diese Threads mit unterschiedlichen Werten).

Vielen Dank.

+0

Können Sie das umfassendere Problem, das Sie lösen, näher erläutern? Was ich sehen kann, ist eine mögliche Lösung, die Werte in einer Menge zu speichern und Accessor-Funktionen zu erstellen, so dass ein Thread einen Mutex erwerben muss, um die Set-Mitgliedschaft zu ändern. Auf diese Weise haben Sie eine synchronisierte Möglichkeit für Threads, um "$ value" zu "checken" und "einzuchecken". – aednichols

+0

Ich versuche, eine Race Condition im Web zu lösen, so dass die Benutzer einen Algorithmus auslösen, um einige Berechnungen (relativ teuer und zeitaufwendig) für ein Objekt mit einer ID durchzuführen. Die Idee ist also, basierend auf dieser ID, "Warteschlange" oder einfach die Anfragen zu blockieren und sie einzeln zu bearbeiten. Wenn ich die gleichzeitige Ausführung der Anfrage für dieselbe ID zulasse, kann die vorherige Berechnung verloren gehen. Der Punkt ist jedoch, dass Anforderungen für unterschiedliche IDs gleichzeitig ohne jeglichen Nachteil ausgeführt werden können. – carlosV2

+0

Ist das Ergebnis der Berechnung für eine bestimmte ID jedes Mal gleich? Klingt wie du solltest [Memoisierung] (https://en.wikipedia.org/wiki/Memoization) – aednichols

Antwort

0

https://github.com/arvenil/ninja-mutex

Herde/mysql/redis/memcache Adapter

Sie können sie alle, und wählen Sie die man versuchen, die für Sie

könnte wie folgt aussehen
<?php 
require 'vendor/autoload.php'; 

use NinjaMutex\Lock\MemcacheLock; 
use NinjaMutex\MutexFabric; 

$memcache = new Memcache(); 
$memcache->connect('127.0.0.1', 11211); 
$lock = new MemcacheLock($memcache); 
$mutexFabric = new MutexFabric('memcache', $lock); 
if ($mutexFabric->get($value)->acquireLock(1000)) { 
    // Do some very critical stuff 

    // and release lock after you finish 
    $mutexFabric->get($value)->releaseLock(); 
} else { 
    throw new Exception('Unable to gain lock for very critical stuff!'); 
} 

In Ihrem Fall Beispiel funktioniert