Lock non bloquant versus lock bloquant ?

  • Auteur de la discussion Auteur de la discussion ortolojf
  • Date de début Date de début
WRInaute accro
Bonjour

C'est pour la classe class_cache.inc.php de cache html de noren, et aussi pour mon site web.

Je cherche à faire une classe de gestion d'accès à une ressource en lecture/écriture, de telle manière que, si le fichier/ressource existe, on y accède en lecture, sinon le processus est censé écrire dedans, sans que d'autres processus ne puissent écrire en même temps.

J'hésite entre un lock bloquant et un lock non bloquant.

PHP ne permet pas théoriquement, les locks non bloquants, du moins de savoir si la ressource est disponible ou non, d'une manière suffisamment atomistique, avant le lock.

Mais, sur le PHP Manual, il y a cette classe ci-dessous ( transformée en classe par mes soins ).

Quelle est a meilleure solution, du point de vue rapidité ? Bloquant ou non bloquant ?

Pour le cache, la durée de la tâche est celle du chargement de la page.

Pour le reste, c'est un peu plus court

Merci beaucoup pour vos réponses.

Amicalement.


PHP:
<?php

class Semaphore_non_blocking {
        const SHARED_MEMORY = 100;
        public $fp_log                = null;
        private $projectId            = null;
        private $resourceSemaphore    = null;
        private $tokenSemaphore        = null;
        private $tokenValue            = null;
        private $resourceSemaphoreKey    = null;
        private $tokenSemaphoreKey        = null;
        private $tokenValueKey            = null;
        public function __construct($filename, $is_cache = false) {
            if($is_cache === false) {
                $this->projectId    = "aplusbegalix";
            } else {
                $this->projectId    = "abraracourcix";
            }
            $var = $filename . "_" . $this->projectId;
            /**
                $this->fp_log = fopen(basename($filename) . ".log", "w+");
                if($this->fp_log === false) {
                        echo "failed to open : " . $filename . ".log" . "<br />\n";
                        return false;
                }
                **/
                $this->resourceSemaphoreKey    = (int)preg_replace("/[^0-9]/","",(preg_replace("/[^0-9]/","",md5($var))/35676248)/619876); // text to number system.
                $this->tokenSemaphoreKey    = $this->resourceSemaphoreKey + 1387655434;
                $this->tokenValueKey        = $this->resourceSemaphoreKey + 2386421167;
                $tmp_array = array('$this->resourceSemaphoreKey' => $this->resourceSemaphoreKey,
                        '$this->tokenSemaphoreKey' => $this->tokenSemaphoreKey,
                        '$this->tokenValueKey' => $this->tokenValueKey);
                //    $this->myEcho(var_export($tmp_array, true));
                if(($this->resourceSemaphoreKey    == -1) ||
                        ($this->tokenSemaphoreKey == -1) ||
                        ($this->tokenValueKey == -1)) {
                        echo "failed to get key of semaphore. <nbr />\n";
                        return false;
                }
                $this->resourceSemaphore = sem_get($this->resourceSemaphoreKey, 1, 0666, true);
                $this->tokenSemaphore = sem_get($this->tokenSemaphoreKey, 1, 0666, true);
                $this->tokenValue = shm_attach($this->tokenValueKey, self::SHARED_MEMORY, 0666);
                if(($this->resourceSemaphore === false) ||
                        ($this->tokenSemaphore === false) ||
                        ($this->tokenValue === false)) {
                        echo "failed to get semaphore. <nbr />\n";
                        return false;
                }
                $this->LOCK();
                return $this;
        }
        public function __destruct() {
                $this->UNLOCK();
//                fclose($this->fp_log);
                @shm_remove($this->tokenValue);
                @shm_detach($this->tokenValue);
                @sem_remove($this->tokenSemaphore);
                @sem_remove($this->resourceSemaphore);
        }
        private function myEcho($v) {
//            echo  microtime() . ' ' . $v . "\n";
//            fputs($this->fp_log, microtime() . ' ' . $v . "\n");
        }
        public function try_lock() {
                //    $this->myEcho('begin try_lock()');
                //    $this->myEcho('acquire token semaphore');
                sem_acquire($this->tokenSemaphore);
                //    $this->myEcho('    token semaphore acquired');
                $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                //    $this->myEcho('    token value: ' . var_export($tmp, true));
                $exit = $tmp;
                if (!$exit) {
                        $tmp = @shm_put_var($this->tokenValue, $this->tokenValueKey, true);
                        $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                        //    $this->myEcho('    token new value: ' . var_export($tmp, true));
                }
                //    $this->myEcho('release token semaphore');
                sem_release($this->tokenSemaphore);
                if ($exit) return false;
                //    $this->myEcho('acquire resource semaphore');
                sem_acquire($this->resourceSemaphore);
                //    $this->myEcho('    resource semaphore acquired');
                return true;
        }
        private function release() {
                //    $this->myEcho('release resource semaphore');
                sem_release($this->resourceSemaphore);
                //    $this->myEcho('acquire token semaphore');
                sem_acquire($this->tokenSemaphore);
                //    $this->myEcho('    token semaphore acquired');
                $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                //    $this->myEcho('    token value: ' . var_export($tmp, true));
                $tmp = @shm_put_var($this->tokenValue, $this->tokenValueKey, false);
                $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                //    $this->myEcho('    token new value: ' . var_export($tmp, true));
                //    $this->myEcho('release token semaphore');
                sem_release($this->tokenSemaphore);
        }
        private function LOCK() {
                for ($triesLeft = 5; $triesLeft > 0 && !$this->try_lock(); $triesLeft--) {
                        //    $this->myEcho('failed to acquire resource');
                        //    $this->myEcho('wait for 1 sec');
                        usleep(1000);
                        //    $this->myEcho('try again');
                }
                //paste here your code, accessing your resource
//                $this->release();
        }
        private function UNLOCK() {
                $this->release();
        }
}
?>
 
WRInaute accro
Rebonjour

A propos des mémoires partagées :

Mon nombre max de segments est : 1024.

Celà veut-il dire que je n'ai le droit de faire 1024 shm_attach() maximum ?

Dans ce cas, comment augmenter 1024 ?

Chaque shm occupe théoriquement 100 octets.

J'ai fait un "ramasse-miettes" des mémoires partagées, ne supprimant que les shm créés par Nginx.

Est-il envisageable, de lancer ce ramasse-miette par crontab régulièrement, en laissant les shm au lieu de les supprimer avec shm_remove() dans le destructeur de mon script ci-dessus ?

Ces suppressions n'entraînent-ils pas des erreurs dans mon script ?

Merci beaucoup.
 
WRInaute accro
Excusez-moi

J'ai l'intention de tweaker mes variables shm de configuration dans /etc/sysctl.conf.

J'aurais besoin de savoir leurs significations.

Voici ci-dessous un exemple de config pour mes 8 Go de RAM ( VPS de OVH ).

Est-ce que des valeurs trop élevées de kernel.shmmni seraient gênantes ?

kernel.shmseg peut rester à 4096.

Merci beaucoup de vos réponses


Code:
    RAM = 8 * (1024 ** 3)

    PAGE_SIZE     => 4096

    kernel.shmmax = RAM / 2.    //    maximum size of a shared memory segment (in pages)
    kernel.shmmax = RAM / 2 = (kernel.shmall*PAGE_SIZE)

    kernel.shmmin: 1            //    minimum size    of a shared memory segment  (in bytes)

    > 4096 ?
    kernel.shmmni:                //    maximum number of shared memory segments.

    <= 4096 ?
    <= kernel.shmmni
    kernel.shmseg:                //    maximum number of shared memory segments / process.

    kernel.shmall                //    total amount of shared memory (in pages).
    kernel.shmall = ceil(kernel.shmmax/PAGE_SIZE).

    kernel.shm_use_phys: 0        //
 
WRInaute accro
Pardon

Pour les intéressés par le concept de lock non bloquant, dernière version :

Je ne fais plus de remove de shm, les shm restent en RAM jusqu'à ce qu'elles soient supprimées par le programme delete_shm.php lancé par crontab toutes les trente minutes.

Le fichier $filename doit représenter la ressource faisant l'objet du lock.

Le paramètre cache, c'est si on utilise la classe de cache html de noren ou non.

Le LOG_FILE se remplit dès qu'il y a au moins un lock non immédiat.

Pour l'instant, depuis ce matin, il n'y a rien dedans.

La fonction micro_sleep($usec), attend $usec micro secondes.

Elle utilise la fonction time_nano_sleep(), ou usleep() sinon.

Maintenant, je vais loguer en Javascript les points de ralentissement de mon site.

Pour l'instant, j'ai 99%, 97%, et 100% pour : Performances, Accessibilité, et le reste.

Bien à vous.



PHP:
<?php
class Semaphore_non_blocking {
    const SHARED_MEMORY = 100;
    const LOG_FILE = "/var/www/html/shm_log/cache.txt";
    private $FILE_NAME            = null;
    private $IS_CACHE            = null;
    private $result_lock            = null;
    private $log                = null;
    private $fp_log                = null;
    private $projectId            = null;
    private $resourceSemaphore    = null;
    private $tokenSemaphore        = null;
    private $tokenValue            = null;
    private $resourceSemaphoreKey    = null;
    private $tokenSemaphoreKey        = null;
    private $tokenValueKey            = null;
    public function __construct($filename, $is_cache = false) {
        $this->FILE_NAME = $filename;
        $this->IS_CACHE = ($is_cache === false) ? "FALSE" : "TRUE";
        if($is_cache === false) {
            $this->projectId    = "aplusbegalix";
        } else {
            $this->projectId    = "abraracourcix";
        }
        $var = $filename . "_" . $this->projectId;
        $this->resourceSemaphoreKey    = (int)preg_replace("/[^0-9]/","",(preg_replace("/[^0-9]/","",md5($var))/35676248)/619876); // text to number system.
        $this->tokenSemaphoreKey    = $this->resourceSemaphoreKey + 1387655434;
        $this->tokenValueKey        = $this->resourceSemaphoreKey + 2386421167;
        if(($this->resourceSemaphoreKey    == -1) ||
            ($this->tokenSemaphoreKey == -1) ||
            ($this->tokenValueKey == -1)) {
            echo "failed to get key of semaphore. <br />\n";
            return false;
        }
        $this->resourceSemaphore = sem_get($this->resourceSemaphoreKey, 1, 0666, true);
        $this->tokenSemaphore = sem_get($this->tokenSemaphoreKey, 1, 0666, true);
        $this->tokenValue = shm_attach($this->tokenValueKey, self::SHARED_MEMORY, 0666);
        if(($this->resourceSemaphore === false) ||
            ($this->tokenSemaphore === false) ||
            ($this->tokenValue === false)) {
            echo "failed to get semaphore. <br />\n";
            return false;
        }
        $this->result_lock = $this->LOCK();
        return $this;
    }
    public function __destruct() {
        if($this->result_lock) {
            $this->release();
        }
        //                @shm_remove($this->tokenValue);
        @shm_detach($this->tokenValue);
        @sem_remove($this->tokenSemaphore);
        @sem_remove($this->resourceSemaphore);
    }
    private function myEcho($v) {
        return  "\t\t" . $v  . ' à : ' . microtime(true) . "\n";
    }
    private function try_lock() {
        //    $this->myEcho('begin try_lock()');
        //    $this->myEcho('acquire token semaphore');
        sem_acquire($this->tokenSemaphore);
        //    $this->myEcho('    token semaphore acquired');
        $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
        //    $this->myEcho('    token value: ' . var_export($tmp, true));
        $exit = $tmp;
        if (!$exit) {
            $tmp = @shm_put_var($this->tokenValue, $this->tokenValueKey, true);
            //         $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
            //    $this->myEcho('    token new value: ' . var_export($tmp, true));
        }
        //    $this->myEcho('release token semaphore');
        sem_release($this->tokenSemaphore);
        if ($exit) return false;
        //    $this->myEcho('acquire resource semaphore');
        sem_acquire($this->resourceSemaphore);
        //    $this->myEcho('    resource semaphore acquired');
        return true;
    }
    private function release() {
        //    $this->myEcho('release resource semaphore');
        sem_release($this->resourceSemaphore);
        //    $this->myEcho('acquire token semaphore');
        sem_acquire($this->tokenSemaphore);
        //    $this->myEcho('    token semaphore acquired');
        //            $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
        // $this->myEcho('    token value: ' . var_export($tmp, true));
        $tmp = @shm_put_var($this->tokenValue, $this->tokenValueKey, false);
        //            $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
        //     $this->myEcho('    token new value: ' . var_export($tmp, true));
        //    $this->myEcho('release token semaphore');
        sem_release($this->tokenSemaphore);
    }
    private function LOCK() {
        $this->log = "";
        for ($triesLeft = 1000; $triesLeft > 0 && !$this->try_lock(); $triesLeft--) {
            $this->log .= $this->myEcho('failed to acquire resource at : ' . $triesLeft);
            $this->log .= $this->myEcho('wait for 1/1000 sec');
            micro_sleep(1000);
            $this->log .= $this->myEcho('try again');
        }
        if($triesLeft <= 0) {
            $this->log .= $this->myEcho('hardly failed to acquire resource');
        }
        if(!empty($this->log)) {
            $tmp = "\t\tFILE = " . $this->FILE_NAME . "\t\tCACHE = " . $this->IS_CACHE . "\n";
            $tmp .= $this->log;
               
            file_put_contents(self::LOG_FILE, $tmp, FILE_APPEND);
        }
        if($triesLeft <= 0) {
            return false;
        }
        return true;
        //paste here your code, accessing your resource
        //                $this->release();
    }
}

?>
 
WRInaute accro
Bonjour

Un programme trouvé sur www.php.net

J'ai amélioré ma classe de verrou non bloquant.

Les identificateurs de sémaphores et mémoire partagée sont théoriquement avec le minimum de collision.

L'implémentation dépend du serveur ( 64 / 32 bits ), là c'est pour 64 bits.

Pour verrouiller :

$LOCK = new Semaphore_non_blocking($filename, $is_cache);


Pour déverrouiller ( obligatoire ) :

unset($LOCK);

Voilà le code :

PHP:
<?php
class Semaphore_non_blocking {

        const SHARED_MEMORY = 100;
        const LOG_FILE = "/var/www/html/shm_log/cache.txt";
        private $FILE_NAME            = null;
        private $IS_CACHE            = null;
        private $result_lock            = null;
        private $log                = null;
        private $fp_log                = null;
        private $projectId            = null;
        private $resourceSemaphore    = null;
        private $tokenSemaphore        = null;
        private $tokenValue            = null;
        private $resourceSemaphoreKey    = null;
        private $tokenSemaphoreKey        = null;
        private $tokenValueKey            = null;
        public function __construct($filename, $is_cache = false) {
                $this->FILE_NAME = $filename;
                $this->IS_CACHE = ($is_cache === false) ? "FALSE" : "TRUE";
                if($is_cache === false) {
                        $this->projectId    = "aplusbegalix";
                } else {
                        $this->projectId    = "abraracourcix";
                }
                $var = $filename . "_" . $this->projectId;
                $this->resourceSemaphoreKey    = $this->tmp_ftok($var, "n");
                echo "\t\t" . '$this->resourceSemaphoreKey = ' . $this->resourceSemaphoreKey . "<br /><br />\n";
                $this->tokenSemaphoreKey    = $this->tmp_ftok($var, "s");
                echo "\t\t" . '$this->tokenSemaphoreKey = ' . $this->tokenSemaphoreKey . "<br /><br />\n";
                $this->tokenValueKey        = $this->tmp_ftok($var, "u");
                echo "\t\t" . '$this->tokenValueKey = ' . $this->tokenValueKey . "<br /><br />\n";
                if(($this->resourceSemaphoreKey    === false) ||
                        ($this->tokenSemaphoreKey === false) ||
                        ($this->tokenValueKey === false)) {
                        echo "failed to get key of semaphore. <br />\n";
                        return false;
                }
                $this->resourceSemaphore = sem_get($this->resourceSemaphoreKey, 1, 0666, true);
                $this->tokenSemaphore = sem_get($this->tokenSemaphoreKey, 1, 0666, true);
                $this->tokenValue = shm_attach($this->tokenValueKey, self::SHARED_MEMORY, 0666);
                if(($this->resourceSemaphore === false) ||
                        ($this->tokenSemaphore === false) ||
                        ($this->tokenValue === false)) {
                        echo "failed to get semaphore. <br />\n";
                        return false;
                }
                $this->result_lock = $this->LOCK();
                return $this;
        }
        public function __destruct() {
                if($this->result_lock) {
                        $this->release();
                }
                //                @shm_remove($this->tokenValue);
                @shm_detach($this->tokenValue);
                @sem_remove($this->tokenSemaphore);
                @sem_remove($this->resourceSemaphore);
        }
        private function tmp_ftok($filename = "", $proj = "")
        {
                if(empty($filename))
                {
                        return false;
                }
                $var = $filename . (string)$proj;
                $nbre  = (int)floor(round(hexdec(hash('sha256', $var))) / 2147483647214748364721474836472147483647214748364721474836472147483);
                return $nbre;
        }
        private function myEcho($v) {
                return  "\t\t" . $v  . ' à : ' . microtime(true) . "\n";
        }
        private function try_lock() {
                //    $this->myEcho('begin try_lock()');
                //    $this->myEcho('acquire token semaphore');
                sem_acquire($this->tokenSemaphore);
                //    $this->myEcho('    token semaphore acquired');
                $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                //    $this->myEcho('    token value: ' . var_export($tmp, true));
                $exit = $tmp;
                if (!$exit) {
                        $tmp = @shm_put_var($this->tokenValue, $this->tokenValueKey, true);
                        //         $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                        //    $this->myEcho('    token new value: ' . var_export($tmp, true));
                }
                //    $this->myEcho('release token semaphore');
                sem_release($this->tokenSemaphore);
                if ($exit) return false;
                //    $this->myEcho('acquire resource semaphore');
                sem_acquire($this->resourceSemaphore);
                //    $this->myEcho('    resource semaphore acquired');
                return true;
        }
        private function release() {
                //    $this->myEcho('release resource semaphore');
                sem_release($this->resourceSemaphore);
                //    $this->myEcho('acquire token semaphore');
                sem_acquire($this->tokenSemaphore);
                //    $this->myEcho('    token semaphore acquired');
                //            $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                // $this->myEcho('    token value: ' . var_export($tmp, true));
                $tmp = @shm_put_var($this->tokenValue, $this->tokenValueKey, false);
                //            $tmp = @shm_get_var($this->tokenValue, $this->tokenValueKey);
                //     $this->myEcho('    token new value: ' . var_export($tmp, true));
                //    $this->myEcho('release token semaphore');
                sem_release($this->tokenSemaphore);
        }
        private function LOCK() {
                $this->log = "";
                for ($triesLeft = 1000; $triesLeft > 0 && !$this->try_lock(); $triesLeft--) {
                        if($triesLeft == 1000) {
                                $this->log .= $this->myEcho('failed to acquire resource at : ' . $triesLeft);
                                $this->log .= $this->myEcho('wait for 1/1000 sec');
                        }
                        micro_sleep(1000);
                }
                if($triesLeft < 1000) {
                        $this->log .= $this->myEcho('try again');
                        $tmp = "\t\tFILE = " . $this->FILE_NAME . "\t\tCACHE = " . $this->IS_CACHE . "\n";
                        $tmp .= $this->log;
                        file_put_contents(self::LOG_FILE, $tmp, FILE_APPEND);
                }
                if($triesLeft <= 0) {
                        return false;
                }
                return true;
                //paste here your code, accessing your resource.
        }
}
?>
 
Discussions similaires
Haut