檔案鎖 - PHP 讀檔案怎麼實現加鎖

來源:互聯網
上載者:User
有大量檔案需要處理。
用一個php進程去操作會很慢。

如何在一個進程讀某一個檔案的時候,把檔案鎖上。
不讓其他進程可以再讀而直接跳過,繼續讀其他的?

把正在讀得檔案rename,讀完之後再rename回來,效率挺低的。如果實在沒有更好的方法,就只能用這個了。
flock,測試了一下,貌似不太好用,試了一下,沒實現檔案的非阻塞讀鎖。
給不同進程分配不同的檔案,不好實現。
也沒資料庫。就算有。用資料庫做鎖,貌似比rename更低效。

請問有什麼更好的方式可以給檔案加 讀鎖。因為,只需要讀檔案。

回複內容:

有大量檔案需要處理。
用一個php進程去操作會很慢。

如何在一個進程讀某一個檔案的時候,把檔案鎖上。
不讓其他進程可以再讀而直接跳過,繼續讀其他的?

把正在讀得檔案rename,讀完之後再rename回來,效率挺低的。如果實在沒有更好的方法,就只能用這個了。
flock,測試了一下,貌似不太好用,試了一下,沒實現檔案的非阻塞讀鎖。
給不同進程分配不同的檔案,不好實現。
也沒資料庫。就算有。用資料庫做鎖,貌似比rename更低效。

請問有什麼更好的方式可以給檔案加 讀鎖。因為,只需要讀檔案。

你的問題是:
1. 很多檔案,想多進程處理,以提高效率,縮短總處理時間
2. 這些進程只需要讀檔案,不需要寫
3. 對每個檔案,只要有一個進程處理過它就可以了,沒有多個進程都必須處理它的需求

你的需求其實是分治,將檔案分為多個組(不一定要在檔案系統上建立目錄),然後分而治之,這種情況不需要用鎖.

鎖不是用於這種情境的,鎖用於下面這種情境:

1. 檔案file.txt裡面記錄了user1的銷售額和user2的銷售額,user1+user2的銷售總額
2. 進程php1負責寫入user1的資料,進程php2負責寫入user2的資料,兩個進程各讀出銷售總額顯示給user1,user2
3. user1和user2同時要求寫入,真的是同時,不是前後差個幾秒什麼的

建議你這樣解決:
1. 啟動多個PHP進程(nohup php your_script.php your_dir &)
2. 每個PHP進程賦予一個序號(假設4個進程,那就0,1,2,3),可以通過對進程自身的pid模運算取餘數得到,也可以在啟動進程的時候通過命令列傳入,隨你了
3. 每個進程在處理檔案前先對檔案名稱做crc32()運算,模一下進程總數: crc32(file_name) % 4, 模數結果與此進程的序號相等就讀取內容並處理,不相等就跳過

最後:小編幫我排個版吧...

  1. 如@felix021 所說,flock($res, LOCK_EX|LOCK_NB) 是有效,請好好看文檔……
  2. @賣掉內褲去上網 所說,memcached 雖然是純記憶體操作,但畢竟有網路或unix domain socket開銷,為了一個檔案鎖去啟動一個Memcached未免太浪費。Linux中可以使用共用記憶體來做鎖,請參考php手冊中 shm_has_var / shm_put_var 。
  3. 如你自己說的,每進程分配一個專有檔案也是可以的,並不是很麻煩,如果所有背景工作處理序都有一個主進程fork出來就更方便了,最簡單最dirty的辦法是,把檔案名稱放在主進程數組裡,每次fork之前,就pop出來一個檔案名稱……
  4. 用檔案rename的方法跟@賣掉內褲去上網 說的依靠判斷一個lock檔案存在與否的辦法開銷差不多,如果你的檔案數不是很多,鎖搶佔不頻繁,可以這麼做……

除了檔案鎖以外,其他自行實現的鎖在有鎖進程意外退出時,都需要自行實現解鎖機制。所以,還是推薦用檔案鎖,會由系統來自動釋放……

關於flock的示範

function do_flock(){    ob_implicit_flush(true); //關閉PHP輸出緩衝    $file = __FILE__;    $f = fopen($file, 'r');    $count = 0;    while(1){      $locked = flock($f, LOCK_NB | LOCK_EX);      if($locked) {        echo "GOT LOCK\n";        sleep(10);        flock($f, LOCK_UN);        echo "RELEASE LOCK\n";        break;      } else {        echo 'LOCKED BY OTHER, WAIT:' . ($count ++) . "\n";        sleep(1);      }       }   }

測試方法:

time curl --no-buffer "http://localhost/flock"//在10秒鐘之內另外一個terminal裡再執行相同命令

Terminal 1 輸出:

GOT LOCKRELEASE LOCKreal0m10.023suser0m0.008ssys0m0.008s

Terminal 2 輸出:

LOCKED BY OTHER, WAIT:0LOCKED BY OTHER, WAIT:1LOCKED BY OTHER, WAIT:2LOCKED BY OTHER, WAIT:3LOCKED BY OTHER, WAIT:4LOCKED BY OTHER, WAIT:5LOCKED BY OTHER, WAIT:6LOCKED BY OTHER, WAIT:7LOCKED BY OTHER, WAIT:8GOT LOCKRELEASE LOCKreal0m19.025suser0m0.008ssys0m0.008s

Ubuntu 12.04 測試通過,沒有Mac沒法測,但應該沒啥問題,畢竟是同根同源的,PHP源碼裡也只是對Win有特殊實現……

注意,以下情況會影響輸出效果

  1. 瀏覽器有渲染緩衝,webkit核心的瀏覽器大概需要額外輸出4k位元組的空白才會開始渲染輸出
  2. 如果用FastCGI方式部署的PHP,Web伺服器可能會有輸出緩衝,我用的Cherokee大概也是4k左右的緩衝

針對這些緩衝,可以在每次echo時,把內容用str_pad補齊4096位元組

1. 為什麼你會覺得rename效率低呢?如果一個目錄下的檔案不是相當多的話,這個應該不低。

2. 你肯定沒有好好看flock的文檔.

如果不希望 flock() 在鎖定時堵塞,則給 operation 加上 LOCK_NB(PHP 4.0.1 以前的版本中設定為 4)。

用memcached實現吧。

比如讀取檔案 $filename = "t.txt";

if(!$memcached->get($filename)){   //檔案鎖不存在,那麼執行檔案讀取功能   //首先再將檔案鎖住,   $memcaced->save($filename,'1');   $fs = fopen($filename,'r+');      fclose($fs);   //讀取完畢釋放檔案鎖   $memcaced->delete($filename);}else{   // 檔案鎖已經存在,跳過   }

以上是 memcaced 純記憶體操作,速度會很快,根本不要考慮到效能的問題,當然還有一種方法,採用真正的檔案鎖,即添加一個新檔案的方法控制,檔案爭用,但是此方法將加大IO的開銷。

flock,測試了一下,貌似不太好用,試了一下,沒實現檔案的非阻塞讀鎖。

我記得好像有啊

http://php.net/manual/zh/function.flo...

LOCK_SH 就是讀取鎖,加鎖後,其他程式可以讀取,但不能寫入
LOCK_EX 就是寫入鎖,加鎖後,其他程式不能讀也不能寫
LOCK_NB(Windows不支援) 就是非阻塞模式,得不到鎖立刻返回

我覺得這三個參數組合起來完全可以實現樓主的需求.

最簡單解決辦法,一共倆檔案,一個write,一個read。reader完了等writer close了就對調檔案名稱。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.