En PHP, flock ne semble pas très bien fonctionner ! Dans le cas de la concurrence multiple, il semble que les ressources soient souvent monopolisées et ne soient pas libérées immédiatement, ou pas du tout, provoquant un blocage, entraînant une utilisation très élevée du processeur du serveur et parfois même provoquant la mort complète du serveur. Il semble que cela se produise sur de nombreux systèmes Linux/Unix. Par conséquent, vous devez réfléchir attentivement avant d’utiliser le flock.
Si flock() est utilisé correctement, il est tout à fait possible de résoudre le problème de blocage. Bien sûr, si vous n’envisagez pas d’utiliser la fonction flock(), il y aura également une bonne solution à notre problème. Les solutions sont résumées grossièrement comme suit.
Option 1 : Définir un délai d'attente lors du verrouillage du fichier. La mise en œuvre approximative est la suivante :
if($fp=fopen($fileName,'a')){ $startTime=microtime(); do{ $canWrite=flock($fp,LOCK_EX); if(!$canWrite){ usleep(round(rand(0,100)*1000)); } }while((!$canWrite)&&((microtime()-$startTime)<1000)); if($canWrite){ fwrite($fp,$dataToSave); } fclose($fp); }
Le délai d'attente est fixé à 1 ms. Si le verrouillage n'est pas obtenu dans ce délai, il sera obtenu à plusieurs reprises jusqu'au droit d'actionner le. Le fichier est obtenu, bien sûr. Si le délai d'attente a été atteint, vous devez quitter immédiatement et abandonner le verrouillage pour permettre à d'autres processus de fonctionner.
Option 2 : Ne pas utiliser la fonction flock et utiliser des fichiers temporaires pour résoudre le problème des conflits de lecture et d'écriture. Le principe général est le suivant :
(1) Mettez une copie du fichier qui doit être mis à jour dans notre répertoire de fichiers temporaires, enregistrez l'heure de la dernière modification du fichier dans une variable et choisissez-en une au hasard. pour ce fichier temporaire, ce qui n'est pas facile dupliquer le nom de fichier.
(2) Après avoir mis à jour ce fichier temporaire, vérifiez si l'heure de la dernière mise à jour du fichier d'origine est cohérente avec l'heure précédemment enregistrée.
(3) Si l'heure de la dernière modification est la même, renommez le fichier temporaire modifié en fichier d'origine. Afin de garantir que l'état du fichier est mis à jour de manière synchrone, l'état du fichier doit être effacé.
(4) Cependant, si l'heure de la dernière modification est cohérente avec celle enregistrée précédemment, cela signifie que le fichier d'origine a été modifié pendant cette période, le fichier temporaire doit être supprimé puis renvoyer false, indiquant que le fichier a été modifié à ce moment-là. D'autres processus sont en cours.
Le code d'implémentation est le suivant :
$dir_fileopen='tmp'; function randomid(){ return time().substr(md5(microtime()),0,rand(5,12)); } function cfopen($filename,$mode){ global $dir_fileopen; clearstatcache (); do{ $id=md5(randomid(rand(),TRUE)); $tempfilename=$dir_fileopen.'/'.$id.md5($filename); } while( file_exists ($tempfilename)); if(file_exists($filename)){ $newfile=false; copy($filename,$tempfilename); }else{ $newfile=true; } $fp=fopen($tempfilename,$mode); return $fp?array($fp,$filename,$id,@ filemtime ($filename)):false; } function cfwrite($fp,$string){ return fwrite($fp[0],$string); } function cfclose($fp,$debug='off'){ global $dir_fileopen; $success=fclose($fp[0]); clearstatcache(); $tempfilename=$dir_fileopen.'/'.$fp[2].md5($fp[1]); if((@filemtime($fp[1])==$fp[3])||($fp[4]==true&&!file_exists($fp[1]))||$fp[5]==true){ rename($tempfilename,$fp[1]); }else{ unlink($tempfilename); //说明有其它进程 在操作目标文件,当前进程被拒绝 $success=false; } return $success; } $fp=cfopen('lock.txt','a+'); cfwrite($fp,"welcome to beijing.\n"); fclose($fp,'on');
Pour les fonctions utilisées dans le code ci-dessus, il faut expliquer :
(1) rename(); . Cette fonction ressemble en fait plus à mv sous Linux. Il est pratique de mettre à jour le chemin ou le nom d'un fichier ou d'un répertoire. Mais lorsque je teste le code ci-dessus dans la fenêtre, si le nouveau nom de fichier existe déjà, un avis sera émis indiquant que le fichier actuel existe déjà. Mais ça marche bien sous Linux.
(2) clearstatcache(); clear file status.php mettra en cache toutes les informations d'attribut du fichier pour fournir de meilleures performances, mais parfois, plusieurs processus suppriment ou mettent à jour des fichiers, PHP n'a pas eu le temps de le faire. mettre à jour les attributs du fichier dans le cache, ce qui pourrait facilement conduire au fait que l'heure de la dernière mise à jour consultée ne correspond pas à des données réelles. Vous devez donc ici utiliser cette fonction pour vider le cache enregistré.
Option 3 : Lire et écrire de manière aléatoire les fichiers exploités pour réduire la possibilité de concurrence.
Cette solution semble être utilisée plus souvent lors de l'enregistrement des journaux d'accès des utilisateurs. Auparavant, nous devions définir un espace aléatoire. Plus l'espace est grand, plus la possibilité de concurrence est faible. En supposant que l'espace de lecture et d'écriture aléatoire est [1-500], la distribution de nos fichiers journaux va de log1 à log500. Chaque fois qu'un utilisateur accède, les données sont écrites de manière aléatoire dans n'importe quel fichier compris entre log1 et log500. Dans le même temps, deux processus enregistrent des journaux. Le processus A peut être le fichier log32 mis à jour, mais qu'en est-il du processus B ? Ensuite, la mise à jour à ce moment-là peut être log399. Vous devez savoir que si vous souhaitez que le processus B fonctionne également sur log32, la probabilité est essentiellement de 1/500, ce qui est presque égal à zéro. Lorsque nous devons analyser les journaux d'accès, il nous suffit d'abord de fusionner ces journaux, puis de les analyser. L'un des avantages de l'utilisation de cette solution pour enregistrer les journaux est que la possibilité de mettre en file d'attente les opérations du processus est relativement faible, ce qui permet au processus de terminer chaque opération très rapidement.
Option 4 : Mettre tous les processus à opérer dans une file d'attente. Mettez ensuite un service dédié pour terminer l'opération sur le fichier. Chaque processus exclu dans la file d'attente équivaut à la première opération spécifique, donc pour la première fois, notre service n'a besoin que d'obtenir les éléments d'opération spécifiques de la file d'attente. S'il y a ici un grand nombre de processus d'opération de fichiers, cela n'a pas d'importance. . , faites simplement la queue au fond de notre file d'attente. Tant que vous êtes prêt à faire la queue, la durée de la file d'attente n'a pas d'importance.
Pour les options précédentes, chacune a ses avantages ! Il peut être grossièrement divisé en deux catégories :
(1) la file d'attente est requise (impact lent), comme les options 1, 2 et 4
(2) la file d'attente n'est pas requise. (Impact rapide) Option 3
Lors de la conception du système de mise en cache, nous n'utiliserons généralement pas l'option 3. Parce que le programme d'analyse et le programme d'écriture du Plan 3 ne sont pas synchronisés, lors de l'écriture, la difficulté de l'analyse n'est pas du tout prise en compte, tant que l'écriture est bonne. Imaginez, si nous utilisons également la lecture et l'écriture aléatoires de fichiers lors de la mise à jour d'un cache, il semble que de nombreux processus seront ajoutés lors de la lecture du cache. Mais les options un et deux sont complètement différentes. Bien que le temps d'écriture doive attendre (en cas d'échec de l'acquisition du verrou, il sera acquis à plusieurs reprises), mais la lecture du fichier est très pratique. Le but de l'ajout de cache est de réduire les goulots d'étranglement lors de la lecture des données et ainsi d'améliorer les performances du système.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!