<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      測試PHP幾種方法寫入文件的效率與安全性

      前置條件:

      所有測試生成的都寫入一個新文件,如果是同一個文件名,那么每次執行腳本前,需要把該日志文件刪掉,確保每次執行時日志文件都是重新創建的。

      每次執行都是往日志文件中使用多進程寫入90000行日志。每種方式分成四種對照組測試:

      30*3000 加鎖(即30個進程每個進程寫入3000行,總共90000行,寫入時需對日志文件上獨占鎖)。

      30*3000 不加鎖(即30個進程每個進程寫入3000行,總共90000行,寫入時日志文件不上鎖)。

      90*1000 加鎖(即90個進程每個進程寫入1000行,總共90000行,寫入時需對日志文件上獨占鎖)。

      90*1000 不加鎖(即90個進程每個進程寫入1000行,總共90000行,寫入時日志文件不上鎖)。

       

      方式一:

      使用file_put_contents() 函數寫入文件。為了避免內容覆蓋,須使用FILE_APPEND模式寫入。

      加鎖:(n=3000 | n=1000)

      for($i=0;$i<n,$i++){

        $msg = "test text";

        file_put_contents($log, $msg, FILE_APPEND|LOCK_EX);

      }

       

      不加鎖:(n=3000 | n=1000)

      for($i=0;$i<n,$i++){

        $msg = "test text";

        file_put_contents($log, $msg, FILE_APPEND);

      }

      執行情況如下表:

      序號

      進程數

      每個進程寫入行數

      是否加鎖

      第一次執行平均耗時(s)

      第二次執行平均耗時(s)

      第三次執行平均耗時(s)

      1-1

      30

      3000

      Y

      2.831

      2.815

      2.861

      1-2

      30

      3000

      N

      2.826

      2.855

      2.751

      1-3

      90

      1000

      Y

      2.407

      2.396

      2.278

      1-4

      90

      1000

      N

      1.779

      2.052

      2.01

       

       

      方式二:

      加鎖:(n=3000 | n=1000)

      $handle = fopen($log,’a’);

      flock($handle,LOCK_EX);

      for($i=0;$i<n,$i++){

        $msg = "test text";

        fwrite($handle,$msg);

      }

      flock($handle,LOCK_UN);

      fclose($handle);

       

      不加鎖:(n=3000 | n=1000)

      $handle = fopen($log,’a’);

      for($i=0;$i<n,$i++){

        $msg = "test text";

        fwrite($handle,$msg);

      }

      fclose($handle);

      執行情況如下表:

      序號

      進程數

      寫入行數/每個進程

      是否加鎖

      第一次執行平均耗時(s)

      第二次執行平均耗時(s)

      第三次執行平均耗時(s)

      2-1

      30

      3000

      Y

      0.66

      0.659

      0.658

      2-2

      30

      3000

      N

      1.272

      1.17

      1.161

      2-3

      90

      1000

      Y

      0.83

      0.855

      0.836

      2-4

      90

      1000

      N

      0.952

      1.097

      0.947

       

       

      以方式一跟方式二的表格為參照,同一種方式,上不上鎖,性能相差不是很大,從效率上講,方式二要比方式一高效。

      最根本的原因是file_put_contents()函數每次執行相當于執行了 fopen(),fwrite(),fclose()三個函數,所以單次執行耗時會比較長。

      如果把方式二做個調整,比如把fopen()和fclose都放進for循環里,那么方式二跟方式一基本沒太大差別。比如下面代碼:

      for($i=0;$i<n,$i++){

        $handle = fopen($log,’a’);

        //flock($handle,'LOCK_EX');

        $msg = "test text";

        fwrite($handle,$msg);

        //flock($handle,'LOCK_UN');

        fclose($handle);

      }

       當然,如果用這種寫法本身就不合理,還不如直接使用file_put_contents()來的簡單。

      不上鎖的情況,日志寫進去時無序的,各個進程之間穿插著寫入一行日志。

      上鎖的情況,日志相對有序,基本是一個進程寫完n行后釋放了獨占鎖才輪到另一個進程。但是進程之間也是無序的。比如第一個子進程寫完,被第5個子進程搶到獨占鎖,那么就是第5個子進程先寫,第二個只能繼續等。所以,上鎖的情況同一個進程寫的日志才是有序的。

      <?php
       
      set_time_limit(30);
      $log = '/data/tmp/a.log';
      
      for($i = 0;$i<30;$i++){
          pcntl_signal(SIGCHLD, SIG_IGN);
          $fid = pcntl_fork();
          if($fid === 0){
              try {
              $start = microtime(true);       
              $handle = fopen($log,'a');
              flock($handle,LOCK_EX);
              for($j=0;$j<3000;$j++){ 
                  $start_time = microtime(true);
                  //TODO 其他業務邏輯
                  //打點記錄并行任務執行狀況
                  $fid = posix_getpid();
                  $ffid = posix_getppid();
                  $date = date('YmdHis');
                  $end_time = microtime(true);
                  $usetime = round($end_time-$start_time,2);
                  $msg =  PHP_EOL."序號:{$i}:{$j}; 時間:{$date}; 當前進程ID:{$fid}; 父進程ID:{$ffid}; 任務開始:{$start_time}; 任務結束:{$end_time}; 耗時:{$usetime}";
                  //file_put_contents($log,$msg,FILE_APPEND|LOCK_EX);
                  fwrite($handle,$msg);
              }
              flock($handle,LOCK_UN);
              fclose($handle);
              unset($handle);
              $end = microtime(true);
              $s = round($end-$start,3);echo "進程:{$i},開始:{$start},結束:{$end},耗時:{$s}".PHP_EOL;
              }finally{
                  if(function_exists("posix_kill")){
                      posix_kill(getmypid(),SIGTERM);
                  }else{
                      system('kill -9 '.getmypid());
                  }
              }
          }
      }
      
      echo 'over'.PHP_EOL;

       

      我們如果是使用 fopen($file,'a') 這種模式打開文件,或者file_put_contents($file,$log,FILE_APPEND) 打開文件去寫入,那么寫操作就不從文件描述符的當前位置開始,而是在文件末尾追加寫入,每一行的寫入都是一個獨立的操作,所以基本沒有上鎖的必要。

      系統層面上對每個寫入請求之前的位置更新操作應該具有原子性,且對每個寫操作也是具有完整性保證的。不會導致兩個寫操作交叉執行的情況。

      那么在上鎖的情況下,如果某個子進程在解除文件鎖之前就掛掉了,會不會導致文件被鎖死而導致其他進程一直等待呢?

      這里做個測試:開5個子進程,每個進程寫入5行日志,日志編號序號(子進程編號:日志編號)總共25行日志。

      如果在第三個子進程上了獨占鎖,然后寫入第三行日志前,讓該子進程退出。具體過程如下:

      <?php
      set_time_limit(30);
      $log = '/data/tmp/a.log';
      
      for($i = 1;$i<=5;$i++){
          pcntl_signal(SIGCHLD, SIG_IGN);
          $fid = pcntl_fork();
          if($fid === 0){
              try {
              $start = microtime(true);
              $handle = fopen($log,'a');
              flock($handle,LOCK_EX);
              for($j=1;$j<=5;$j++){
                if($i==3 && $j==3){
                  break;//第三個子進程在寫入第三行日志時退出該子進程
                }
                  $start_time = microtime(true);
                  //TODO 其他業務邏輯
                  //打點記錄并行任務執行狀況
                  $fid = posix_getpid();
                  $ffid = posix_getppid();
                  $date = date('YmdHis');
                  $end_time = microtime(true);
                  $usetime = round($end_time-$start_time,2);
                  $msg =  "序號:{$i}:{$j}; 時間:{$date}; 當前進程ID:{$fid}; 父進程ID:{$ffid}; 任務開始:{$start_time}; 任務結束:{$end_time}; 耗時:{$usetime}".PHP_EOL;
                  fwrite($handle,$msg);
              }
              flock($handle,LOCK_UN);
              fclose($handle);
              unset($handle);
              $end = microtime(true);
              $s = round($end-$start,3);
              echo PHP_EOL.$s.',';
              //echo "進程:{$i},開始:{$start},結束:{$end},耗時:{$s}".PHP_EOL;
              }finally{
                  if(function_exists("posix_kill")){
                      posix_kill(getmypid(),SIGTERM);
                  }else{
                      system('kill -9 '.getmypid());
                  }
              }
          }
      }
      
      echo 'over'.PHP_EOL;

      最終得到得日志總數時22行,因為第3個子進程只寫了2行就退出了,執行結果如下圖:

       

      由圖可見,就算第三個子進程中途退出了,沒有釋放日志文件的獨占鎖,但是其他進程仍然正常按照獨占的方式寫入日志。

      原因是當子進程掛掉的時候,該子進程對日志文件的獨占鎖也會被自動解除。所以就算某個子進程上完獨占鎖,沒來得及解除就退出了,也不用擔心會影響到其他進程對該日志文件得使用。

      另外,使用 pcntl_fork() 創建進程時需要注意的一些點

      pcntl_fork()函數執行的時候,會創建一個子進程。該子進程會復制當前進程,也就是父進程的所有的變量數據,代碼,還有狀態。也就是說,在一個子進程創建之前,定義的變量,常量,函數等,在子進程內都可以使用。

      如果創建成功,并且該子進程在父進程內,則返回0,在子進程內返回自身的進程號,失敗則返回-1。

      (1)當我們在 for 循環 或者 foreach 的循環里創建子進程,那么在子進程執行的結尾記得將子進程殺死,不然子進程也會進入 for 循環和 foreach 循環,從而形成遞歸創建子進程的情況。

      例如:

      $arr = array(1,2....n);

      foreach($arr as $k=>$v){
        pcntl_signal(SIGCHLD, SIG_IGN);
        $fid = pcntl_fork();

      }

      或者:

      for($i=1;$i<=n;$i++){

        pcntl_signal(SIGCHLD, SIG_IGN);
        $fid = pcntl_fork();

      }

      這兩種情況最終產生的進程數有 2^n (2的n次方) ,這里面包含一個父進程,出去父進程,就有 2^n -1 個子進程。

      如果我們只是要 n 個子進程去處理,那么,就需要在每個子進程的最后將該子進程殺死。

      例如上面有部分例子的代碼中在 try{} finally {} 中將子進程殺死,不讓其進入遞歸。

      (2)不論時使用for循環還是foreach循環,都不會按照順序去執行。

      比如第(1)部分的兩個例子中,可能最后一個子進程先執行,最終先進入循環遞歸,結果第n個子進程執行了2n次。

      而第一個子進程進程如果最后執行到,就只能執行1次。當然這是在每個子進程執行完沒有殺死的情況。比如:

      <?php
      $pid = $fid = posix_getpid();
      $arr = array('num1','num2','num3','num4');
      foreach($arr as $k=>$v){
              pcntl_signal(SIGCHLD, SIG_IGN);
              $fid = pcntl_fork();
              if($fid === 0){
                      $fid = posix_getpid();
                      $ffid = posix_getppid();                
                      $msg =  "循環次數{$v};主進程ID:{$pid}; 父進程ID:{$ffid}; 當前進程ID:{$fid};".PHP_EOL;
                      echo $msg;
               }
      }
      ?>      

      結果:

       

      posted @ 2021-02-05 20:03  喜歡哲學的猴子  閱讀(214)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲中文字幕成人综合网| 免费无码AV一区二区波多野结衣 | 波多野结衣的av一区二区三区| 亚洲国产成人无码av在线影院| 久久久久成人精品无码中文字幕| 久久美女夜夜骚骚免费视频| 国产做爰xxxⅹ久久久精华液 | 亚洲V天堂V手机在线| 噜噜综合亚洲av中文无码| 久久人妻国产精品| 我要看亚洲黄色太黄一级黄| 欧美乱码伦视频免费| 天堂中文最新版在线官网在线 | 日韩精品人妻中文字幕| 香蕉EEWW99国产精选免费| 妺妺窝人体色www婷婷| 欧美成人www免费全部网站| 好吊视频在线一区二区三区| 旬邑县| 蜜臀av一区二区三区精品| aaa少妇高潮大片免费看| 精品国产精品午夜福利| 亚洲国产成人久久综合区| 一区二区三区鲁丝不卡| 亚洲成色精品一二三区| 麻豆国产成人AV在线播放| 波多野结衣一区二区免费视频| 亚洲熟女一区二区av| 国产精品久久久久影院老司| 日本一区二区久久人妻高清| 影音先锋啪啪av资源网站| 亚洲av成人在线一区| 成人年无码av片在线观看| 国产亚洲欧洲av综合一区二区三区| 日本精品极品视频在线| 成在线人视频免费视频| 久久精品国产成人午夜福利| 国产美女高潮流白浆视频| 日韩精品国产二区三区 | 蜜臀久久综合一本av| 国产成人一区二区三区视频免费|