14

PHPのドキュメントページにflock()は、IISでの使用は安全ではないことが示されています。すべての状況で信頼できない場合flock、同じことを安全に達成できる別の方法はありますか?

4

7 に答える 7

8

考えられるすべての状況下で同じことを安全に達成するために利用できる代替手段はありません。これはコンピューターシステムの設計によるものであり、クロスプラットフォームコードの仕事は簡単ではありません

を安全に使用する必要がある場合はflock()、代わりにアプリケーションの要件を文書化してください。

または、独自のロックメカニズムを作成することもできますが、それがアトミックであることを確認する必要があります。つまり、ロックをテストする必要があり、ロックが存在しない場合は、その間に他にロックを取得できないことを確認する必要があるときに、ロックを確立する必要があります。

これは、ロックを表すロックファイルを作成することで実行できますが、ロックが存在しない場合に限ります。残念ながら、PHPはそのような方法でファイルを作成するためのそのような関数を提供していません。

または、ディレクトリを作成して結果を操作することもできます。これは、ディレクトリが作成されたときに、ディレクトリがすでに存在する場合mkdir()に返されるためです。truefalse

于 2011-08-06T15:30:43.340 に答える
3

ファイルロックを実装できます-mkdirに基づく読み取り/書き込み操作の周りにパターンのロックを解除します。これはアトミックで非常に高速だからです。私はこれをストレステストしましたが、mguttとは異なりボトルネックは見つかりませんでした。ただし、デッドロック状態に注意する必要があります。これはおそらくmguttが経験したことです。デッドロックとは、2回のロック試行が互いに待機し続けることです。これは、ロック試行のランダムな間隔で修正できます。そのようです:

// call this always before reading or writing to your filepath in concurrent situations
function lockFile($filepath){
   clearstatcache();
   $lockname=$filepath.".lock";
   // if the lock already exists, get its age:
   $life=@filectime($lockname);
   // attempt to lock, this is the really important atomic action:
   while (!@mkdir($lockname)){
         if ($life)
            if ((time()-$life)>120){
               //release old locks
               rmdir($lockname);
               $life=false;
         }
         usleep(rand(50000,200000));//wait random time before trying again
   }
}

次に、ファイルパスでファイルを操作し、完了したら、次のコマンドを呼び出します。

function unlockFile($filepath){
   $unlockname= $filepath.".lock";   
   return @rmdir($unlockname);
}

スクリプトがロック解除される前に終了した場合に備えて、PHPの最大実行時間のかなり後に、古いロックを削除することを選択しました。より良い方法は、スクリプトが失敗したときに常にロックを解除することです。これにはきちんとした方法がありますが、私は忘れてしまいました。

于 2014-03-19T15:49:53.483 に答える
2

私の提案は、mkdir()の代わりに使用することですflock()。これは、違いを示すキャッシュの読み取り/書き込みの実際の例です。

$data = false;
$cache_file = 'cache/first_last123.inc';
$lock_dir = 'cache/first_last123_lock';
// read data from cache if no writing process is running
if (!file_exists($lock_dir)) {
    // we suppress error messages as the cache file exists in 99,999% of all requests
    $data = @include $cache_file;
}
// cache file not found
if ($data === false) {
    // get data from database
    $data = mysqli_fetch_assoc(mysqli_query($link, "SELECT first, last FROM users WHERE id = 123"));
    // write data to cache if no writing process is running (race condition safe)
    // we suppress E_WARNING of mkdir() because it is possible in 0,001% of all requests that the dir already exists after calling file_exists()
    if (!file_exists($lock_dir) && @mkdir($lock_dir)) {
        file_put_contents($cache_file, '<?php return ' . var_export($data, true) . '; ?' . '>')) {
        // remove lock
        rmdir($lock_dir);
    }
}

今、私たちは同じことを達成しようとしていflock()ます:

$data = false;
$cache_file = 'cache/first_last123.inc';
// we suppress error messages as the cache file exists in 99,999% of all requests
$fp = @fopen($cache_file, "r");
// read data from cache if no writing process is running
if ($fp !== false && flock($fp, LOCK_EX | LOCK_NB)) {
    // we suppress error messages as the cache file exists in 99,999% of all requests
    $data = @include $cache_file;
    flock($fp, LOCK_UN);
}
// cache file not found
if (!is_array($data)) {
    // get data from database
    $data = mysqli_fetch_assoc(mysqli_query($link, "SELECT first, last FROM users WHERE id = 123"));
    // write data to cache if no writing process is running (race condition safe)
    $fp = fopen($cache_file, "c");
    if (flock($fp, LOCK_EX | LOCK_NB)) {
        ftruncate($fp, 0);
        fwrite($fp, '<?php return ' . var_export($data, true) . '; ?' . '>');
        flock($fp, LOCK_UN);
    }
}

重要な部分はLOCK_NB、すべての連続した要求をブロックしないようにすることです。

ロック中にflock()をブロックしたくない場合は、上記の操作の1つにビットマスクとしてLOCK_NBを追加することもできます。

それがなければ、コードは大きなボトルネックになります!

追加の重要な部分はif (!is_array($data)) {です。これは、$dataに次のものが含まれている可能性があるためです。

  1. array()dbクエリの結果として
  2. false失敗のinclude
  3. または空の文字列(競合状態

最初の訪問者が次の行を実行すると、競合状態が発生します。

$fp = fopen($cache_file, "c");

そして、別の訪問者が1ミリ秒後にこの行を実行します。

if ($fp !== false && flock($fp, LOCK_EX | LOCK_NB)) {

つまり、最初の訪問者は空のファイルを作成しますが、2番目の訪問者はロックを作成するためinclude、空の文字列を返します。

そのため、使用することで回避できる多くの落とし穴mkdir()と、その7倍の速度も見られました。

$filename = 'index.html';
$loops = 10000;
$start = microtime(true);
for ($i = 0; $i < $loops; $i++) {
    file_exists($filename);
}
echo __LINE__ . ': ' . round(microtime(true) - $start, 5) . PHP_EOL;
$start = microtime(true);
for ($i = 0; $i < $loops; $i++) {
    $fp = @fopen($filename, "r");
    flock($fp, LOCK_EX | LOCK_NB);
}
echo __LINE__ . ': ' . round(microtime(true) - $start, 5) . PHP_EOL;

結果:

file_exists: 0.00949
fopen/flock: 0.06401

ご覧のとおり、PSfile_exists()の前で使用していますmkdir()。これは、私のテスト(ドイツ語)でmkdir()のみを使用した場合にボトルネックが発生したためです。

于 2011-10-28T09:48:15.163 に答える
2

これが私の「PHPflock()の代替」です-に基づいて構築しmkdir()ます。

mkdir()でそれを行うというアイデアは、ここここから生まれました。

私のバージョン

  • すでにロックアクセスを取得しているかどうかを確認します。また、同じbasedir.nameに対してクラスを複数回作成して使用した場合に、自分自身をブロックすることを防ぎます。
  • ロックアクセスを要求しているロックファイルが作成されたかどうかを確認します
  • 要求した順番でロックアクセスを取得できます
  • 指定した時間内にロックアクセスを取得できなかった場合、待機とループを停止します
  • デッドロックファイル(= PIDのSIDがもう存在しないファイル)を削除します

次のようにPHPクラスを使用できます。

//$dir        (string) = base-directory for the lock-files (with 'files' I mean directories => mode 0644)
// 2       (float/int) = time to wait for lock-access before returning unsuccessful (default is 0 <= try once and return)
//'.my_lock'  (string) = the way you want to name your locking-dirs (default is '.fLock')
$lock = new FileLock($dir, 2, '.my_lock');

//start lock - a locking directory will be created looking like this:
//$dir/.my_lock-1536166146.4997-22796
if ($lock->lock()) {
    //open your file - modify it - write it back
} else { /* write alert-email to admin */ }

//check if I had locked before
if ($lock->is_locked) { /* do something else with your locked file */ }

//unlock - the created dir will be removed (rmdir)
$lock->unlock();

労働者階級は次のとおりです。

//build a file-locking class
define('LOCKFILE_NONE', 0);
define('LOCKFILE_LOCKED', 1);
define('LOCKFILE_ALREADY_LOCKED', 2);
define('LOCKFILE_ALREADY_LOCKED_IN_OTHER_CLASS', 3);
define('LOCKFILE_FAILED_TO_OBTAIN_LOCK', false);
define('LOCKFILE_FAILED_TO_OBTAIN_LOCK_BY_TIMEOUT', '');


class FileLock {
    //FileLock assumes that there are no other directories or files in the
    //lock-base-directory named "$name-(float)-(int)"
    //FileLock uses mkdir() to lock. Why?
    //- mkdir() is atomic, so the lock is atomic and faster then saving files.
    //  Apparently it is faster than flock(), that requires several calls to the
    //  file system.
    //- flock() depends on the system, mkdir() works everywhere.

    private static $locked_memory = array();

    public function __construct($lockbasedir, $wait_sec=0, $name='.fLock') {
        $this->lockbasedir = (string)$lockbasedir;
        $this->wait        = (float)$wait_sec;
        $this->name        = (string)$name;

        $this->pid         = (int)getmypid();

        //if this basedir.name was locked before and is still locked don't try to lock again
        $this->is_locked   = empty(self::$locked_memory[$this->lockbasedir . $this->name]) ? LOCKFILE_NONE : LOCKFILE_ALREADY_LOCKED;
    }

    public function lock() {
        if ($this->is_locked) return $this->is_locked;

        $break_time = microtime(true);

        //create the directory as lock-file NOW
        $this->lockdir = "{$this->name}-" . number_format($break_time, 4, '.', '') . "-{$this->pid}";
        @mkdir("{$this->lockbasedir}/{$this->lockdir}", 0644);

        $break_time += $this->wait;

        //try to get locked
        while ($this->wait == 0 || microtime(true) < $break_time) {

            //get all locks with $this->name
            $files = preg_grep("/^{$this->name}-\d+\.\d+-\d+$/", scandir($this->lockbasedir));

            //since scandir() is sorted asc by default
            //$first_file is the next directory to obtain lock
            $first_file = reset($files);

            if (!$first_file) {
                //no lock-files at all
                return $this->is_locked = LOCKFILE_FAILED_TO_OBTAIN_LOCK;
            } elseif ($first_file == $this->lockdir) {
                //Its me!! I'm getting locked :)
                self::$locked_memory[$this->lockbasedir . $this->name] = 1;
                return $this->is_locked = LOCKFILE_LOCKED;
            } elseif (preg_match("/^{$this->name}-\d+\.\d+-{$this->pid}$/", $first_file)) {
                //my process-ID already locked $this->name in another class before
                rmdir("{$this->lockbasedir}/{$this->lockdir}");
                $this->lockdir = $first_file;
                self::$locked_memory[$this->lockbasedir . $this->name] = 1;
                return $this->is_locked = LOCKFILE_ALREADY_LOCKED_IN_OTHER_CLASS;
            }

            //missing lock-file for this job
            if (array_search($this->lockdir, $files) === false) return LOCKFILE_FAILED_TO_OBTAIN_LOCK;

            //run only once
            if ($this->wait == 0) break;

            //check if process at first place has died
            if (!posix_getsid(explode('-', $first_file)[2])) {
                //remove dead lock
                @rmdir("{$this->lockbasedir}/$first_file");
            } else {
                //wait and try again after 0.1 seconds
                usleep(100000);
            }
        }

        return $this->is_locked = LOCKFILE_FAILED_TO_OBTAIN_LOCK_BY_TIMEOUT;
    }

    public function unlock($force=false) {
        if ($force || $this->is_locked == 1) {
            rmdir("{$this->lockbasedir}/{$this->lockdir}");
            self::$locked_memory[$this->lockbasedir . $this->name] = $this->is_locked = LOCKFILE_NONE;
        }
    }
}
于 2018-09-05T17:01:46.567 に答える
0

この質問は数年前のものであることに感謝しますが、群れの実用的な例/交換は構築する価値があるかもしれないとちょっと感じました。私はこれを他の答えに基づいていますが、(同時にファイルを書き込むのではなく)群れの機能を純粋に置き換えることを探している人にとっては(これはPHPの手動群れの例を反映していますが)次のように十分だと思います

function my_flock ($path,$release = false){
    if ($release){
        @rmdir($path);
    } else {
        return !file_exists($path) && @mkdir($path);
    }
}
于 2016-09-23T09:46:30.930 に答える
0

mkdirに基づく:

// call this always before reading or writing to your filepath in concurrent situations
function lockFile($filepath){
   clearstatcache();
   $lockname=$filepath.".lock";
   // if the lock already exists, get its age:
   $life=@filectime($lockname);
   // attempt to lock, this is the really important atomic action:
   while (!@mkdir($lockname)){
     if ($life)
        if ((time()-$life)>120){
           //release old locks
           rmdir($lockname);
     }else $life=@filectime($lockname);
     usleep(rand(50000,200000));//wait random time before trying again
   }
}

スクリプトがロック解除される前に終了し、同時に1つ(または複数のスクリプト)が$ life = @ filectime($ lockname);に結果をもたらさない場合に、1つのスクリプトがデッドロックを回避するため。すべてのスクリプトが同時に開始され、ディレクトリがまだ作成されていないためです。ロックを解除してから電話するには:

function unlockFile($filepath){
   $unlockname= $filepath.".lock";   
  return @rmdir($unlockname);
}
于 2019-04-15T16:12:08.610 に答える
0

これらのメソッドはどれも完全にアトミックではありません。

私はこれを確認して、いくつかのテストを行いました。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください

KB単位のサイズで名前が付けられた7つのファイルを使用するT7のコード:

clearstatcache();
$_DEBUG_ = false;

echo "Lock and flush tester.".time()."<br>";
$time_constant = 1570787996;
die; // Remove this line when you set time_constant 

while ( time()<$time_constant )
 {
 usleep(500);
 }


function test($n, $p, $_DEBUG_){
//  $delay_multiplier = $n*2.5;
  $sname = "$n";    // source
  $tname = "$n.txt";// target
  echo "<h4>$n at ".time()."</h4>";
  for ($i = 0; $i<50; $i++ ){
    $start = microtime(true);
    clearstatcache(); // needed for filesize and touch    
    $st = stat("$sname");
    $original_size = $st['size'];
    if ( $_DEBUG_ )
      echo "; 1) prevAccess by ".$st['mtime']." fsize ".$st['size']."; ";
    $fsize = filesize($sname);
    if ( $original_size <> $fsize )
      die("; fsize total FAILTURE; ");
    if ($fsize === 0)
     echo "! <b>The fsize is 0</b>: stat(): ".$st['size']." ;";    
    else
      {
      // READ OPERATION AND LOCK FOR SHARE
       $locked = false;     
       for ($c = 0; !$locked; $c++):      
         if ( $c > 400)
           break;
         $fp = fopen($sname, "r");
         $locked = flock($fp, LOCK_SH);
         if ($locked)
           break;
         else
           {
           echo "failed to get LOCK_SH;<br>";
           usleep(5000);
           }
       endfor;
       $s = fread($fp, $fsize );
       $success = flock($fp, LOCK_UN);
       if ( $success === false  )
         die("; r flock release failed; ");
       $success = fclose($fp);
       if ( $success === false  )
         die("; fclose failed; ");
       // 10 - loaded data , $p - broser
       if ( $success )
         { 
         $result = touch("$sname",strlen($s),$p);
         if ( $_DEBUG_ )
            echo "; TOUCH: $result;";
         }
       else
         die("fclose FAIL.");
       if ( strlen($s)<60 ) 
          echo "*$s LENGTH:".strlen($s)."<br>";
      }
    clearstatcache();
    $st = stat("$tname");                               
    if ( $_DEBUG_ )
      echo "; 2) prevAccess by ".$st['mtime']." fsize is ".$fsize."; ";

    // WRITE OPERATION WITH LOC_EX
    $fp = fopen($tname, "w");
    $locked = false; 
    /*
    // TOTO NEMÁ VLIV NA ZAMKNUTÍ
    for ($c = 0; !$locked; $c++ ):
      $c++;
      if ( $c > 400)
        break;
      $locked = flock($fp, LOCK_EX);
      if ($locked)
        break;
      else
        {
        echo "failed to get LOCK_EX;<br>";
        usleep(5000);
        }
    endfor;
    */
    $locked = flock($fp, LOCK_EX);
    if ( $locked ) {  // acquire an exclusive lock
        $success = fwrite($fp, $s);
        if ( $success === false)
          echo "; w FAILED;";
        else
          if ( $_DEBUG_ )
                echo " $success B written; ";
        $success = fflush($fp);// flush output before releasing the lock
        if ( $success === false ) 
          echo "; flush FAILED; ";
        $success = flock($fp, LOCK_UN);    // release the lock
        if ( $success === false ) 
          echo "; release FAILED; ";
        $success = fclose($fp);
        if ( $success === false ) 
          echo "; fclose FAILED; ";
        clearstatcache(); // needed for filesize and touch
        $fsize = filesize($tname);
        if ($original_size>$fsize)
            {
            echo "; <b>WRITE FAILED, restoring</b>;";
            $original_fname = "$n";
            $result = copy($original_fname, $tname);
            if ($result == false )
              die(" <b>TOTAL FAILTURE: copy failed.</b>");
            else
              echo " <b>RESTORED</b>;";
            }
        else
        {
          if ($fsize === 0)
           echo "! THE FILE WAS NOT WRITTEN: data length: ".strlen($s)." fsize: $fsize RESOURCE: $fp<br>";    
          if ( $success ) 
              touch("$tname",$fsize,$p);
        }
    } else {
        echo "Couldn't get the lock!";
    }
     $time_elapsed_secs = microtime(true) - $start;
     //usleep( $delay_multiplier + $n*rand(2,6) ); 
     if ( $time_elapsed_secs === 0 )
       echo " FAILED ";
    echo "time: $time_elapsed_secs s<br>"; 
  }
}
// headers to identify originator of the request
switch ( $_SERVER['HTTP_USER_AGENT'] ):
  // FF 1:
  case "Mozilla/5.0 (Windows NT 5.1;) Gecko": 
    $p = 1; break;
  // Chrome:
  case "Mozilla/5.0 (Windows NT 5.1) AppleWebKit Chrome  Safari":
    $p = 2; break;
  // OPERA:
  case "Mozilla/5.0 (Windows NT 5.1) AppleWebKit Chrome Safari":  
    $p = 3; break;
endswitch;

copy("523","523.txt");
copy("948","948.txt");
copy("1371","1371.txt");
copy("1913","1913.txt");
copy("2701","2701.txt");
copy("4495","4495.txt");
copy("6758","6758.txt");

test("523",$p,$_DEBUG_);
test("948",$p,$_DEBUG_);
test("1371",$p,$_DEBUG_);
test("1913",$p,$_DEBUG_);
test("2701",$p,$_DEBUG_);
test("4495",$p,$_DEBUG_);
test("6758",$p,$_DEBUG_);

T8(mkdirロックテスト)のコード:

clearstatcache();
$_DEBUG_ = false;

echo "Atomicity tester.".time()."<br>";
$time_constant = 1570787996;
die; // Remove this line when you set time_constant 

while ( time()<$time_constant )
 {
 usleep(500);
 }

/*
c is counter for optimalization
first call must have c = 0;
*/
function atomicFuse($n, $c, $disableDelay = false){
  $start = false;
  if ( !file_exists("$n.t") ) 
   $start = mkdir("$n.t");
  if ( !$disableDelay ){
    if ( $start == false )
     {
     $n = $n*30;
     switch($c):      // Delay example increase:
       case 0: break; // 0,01569 total
       case 1: break; // 0,03138 total
       case 2: $n = $n*2; break; // 0,06276 total
       case 3: $n = $n*4; break; // 0,12552 total
       // case 4: You need at least *6 or *8 to get out of problems with extrem times
       case 4: $n = $n*8; break; // 0,25104 t.(upper limit)
       // In case of heavy traffic:
       case 5: $n = $n*8; break; // 0,36087 total extrem
       case 6: $n = $n*10; break; // 0,51777 total extrem
       case 7: $n = $n*20; break; // 1,03554 total extrem
       default: $n = $n*8; break;
     endswitch;
     usleep($n);
     echo ($n)."<br>";
     }
    }
  return $start;
}
function test($n, $p, $_DEBUG_){
  $fp = null;
  $sname = "$n";    // source
  $tname = "$n.txt";// target
  echo "<h4>$n at ".time()."</h4>";
  for ($i = 0; $i<50; $i++ ){
    $start_time = microtime(true);
      {
      $start = atomicFuse($n,0);
      if (!$start) $start = atomicFuse($n,1);
      if (!$start) $start = atomicFuse($n,2);
      if (!$start) $start = atomicFuse($n,3);
      if (!$start) $start = atomicFuse($n,4);
      if (!$start) $start = atomicFuse($n,5);
      if (!$start) $start = atomicFuse($n,6);
      if (!$start) $start = atomicFuse($n,7);
      if (!$start) $start = atomicFuse($n, false);
      if (!$start) echo "<b>Atomicity failed.</b> ";
      if ( $start )
         {
         echo "<b>Atomicity OK.</b> ";
         /////////////////////////////
         // CHECK FILESIZE VALIDITY //
         /////////////////////////////
         clearstatcache(); // needed for filesize and touch    
         $st = stat("$sname");
         $original_size = $st['size'];
         if ( $_DEBUG_ )
           echo "; 1) prevAccess by ".$st['mtime']." fsize ".$st['size']."; ";
         $fsize = filesize($sname);
         if ( $original_size <> $fsize )
           die("; fsize total FAILTURE; ");
         if ($fsize === 0)
          echo "! <b>The fsize is 0</b>: stat(): ".$st['size']." ;";    
         ///////////////////
         // OPEN THE FILE //
         ///////////////////
         $fp = fopen($sname, "r");
         $s = fread($fp, $fsize );
         $success = fclose($fp);
         if ( $success === false  )
           die("; fclose failed; ");
         // 10 - loaded data, $p - browser
         if ( $success )
           { 
           $result = touch("$sname",strlen($s),$p);
           if ( $_DEBUG_ )
              echo "; TOUCH: $result;";
           }
         else
           die("fclose FAIL.");
         if ( strlen($s)<60 ) 
            echo "*$s LENGTH:".strlen($s)."<br>";
         }  
      }
    if ( $start )
      {
      clearstatcache();
      $st = stat("$tname");                               
      if ( $_DEBUG_ )
        echo "; 2) prevAccess by ".$st['mtime']." fsize is ".$fsize."; ";

      // WRITE OPERATION WITH LOC_EX
      $fp = fopen($tname, "w");
      if ( true ) {  // acquire an exclusive lock
          $success = fwrite($fp, $s);
          if ( $success === false)
            echo "; w FAILED;";
          else
            if ( $_DEBUG_ )
                  echo " $success B written; ";
          $success = fflush($fp);// flush output before releasing the lock
          if ( $success === false ) 
            echo "; flush FAILED; ";
          if ( $success === false ) 
            echo "; release FAILED; ";
          $success = fclose($fp);
          if ( $success === false ) 
            echo "; fclose FAILED; ";
          clearstatcache(); // needed for filesize and touch
          $fsize = filesize($tname);
          if ($original_size>$fsize)
              {
              echo "; <b>WRITE FAILED, restoring</b>;";
              $original_fname = "$n";
              $result = copy($original_fname, $tname);
              if ($result == false )
                die(" <b>TOTAL FAILTURE: copy failed.</b>");
              else
                echo " <b>RESTORED</b>;";
              }
          else
            {
              if ($fsize === 0)
               echo "! THE FILE WAS NOT WRITTEN: data length: ".strlen($s)." fsize: $fsize RESOURCE: $fp<br>";    
              if ( $success ) 
                  touch("$tname",$fsize,$p);
            }
          } else {
              echo "Couldn't get the lock!";
             }
      $success = rmdir("$n.t"); // remove atomic fuse
      if ( $success )
        echo "<h4>DIR REMOVED</h4>";
      else
        echo "<h4>DIR NOT REMOVED</h4>";
      } // start
     else 
       echo "skipped"; 
     $time_elapsed_secs = microtime(true) - $start_time;
     if ( $time_elapsed_secs === 0 )
       echo " FAILED ";
     echo "time: $time_elapsed_secs s<br>"; 
  } // for
}

switch ( $_SERVER['HTTP_USER_AGENT'] ):
  case "": 
    $p = 1; break;
  case "":
    $p = 2; break;
  case "":  
    $p = 3; break;
endswitch;

copy("523","523.txt");
copy("948","948.txt");
copy("1371","1371.txt");
copy("1913","1913.txt");
copy("2701","2701.txt");
copy("4495","4495.txt");
copy("6758","6758.txt");

test("523",$p,$_DEBUG_);
test("948",$p,$_DEBUG_);
test("1371",$p,$_DEBUG_);
test("1913",$p,$_DEBUG_);
test("2701",$p,$_DEBUG_);
test("4495",$p,$_DEBUG_);
test("6758",$p,$_DEBUG_);

注:T5-T7-ファイルの損傷がfflushによるものかfwriteによるものかは特定しませんでしたが、これらのテストでこれらのエラーが発生しました。

注:T8-このテストの特定の問題は、テストブロックの開始(テスト関数の開始時)で待機する時間が長すぎることです。7秒待つような遅れさえあります。しかし、私もこれらの数値を削除しようとしましたが、平均値はあまり変化しないため、この変更後もT8の曲線は同じままです。ここでの問題は、ループで遅延を使用することは問題の理想的な解決策ではなく、失敗の可能性がさらに高くなることです。「失敗」とは、実際にはファイルの破損を意味するのではなく、タイムアウトのために特定のアトミックタスクをスキップすることを意味することに注意してください。

于 2019-10-14T05:35:35.820 に答える