ファイルを unlock して問題になるくらいなら、OS 任せにするほうがよい

476 名前: デフォルトの名無しさん  Mail: sage 投稿日: 2008/03/05(水) 23:48:04 
ファイルの排他制御のテストプログラムを書いています。
ただ単に1つのカウントファイルを100万回インクリメントするプログラム

#!/usr/bin/env python

for i in range(1000000) :
  f = open("count-file", "r+")
  fcntl.flock(f.fileno(), fcntl.LOCK_EX)
  cnt = f.readline()
  cnt = int(cnt) + 1
  f.seek(0)
  f.write("%d\n" % cnt)
  fcntl.flock(f.fileno(), fcntl.LOCK_UN)
  f.close()

を同時に2つ実行するとcount-fileの値が
2000000
になるはずが、
1984329
という風に途中で欠けてしまいます。但し1つ実行する分には正常に動作します。
排他制御がうまくいってないようなのですがどこがいけないのでしょうか。
flockの部分をlockfにしても変化はありません。

OS Gentoo、python 2.5.1


477 名前: デフォルトの名無しさん  Mail: sage 投稿日: 2008/03/05(水) 23:52:06 
LOCK_UN の前に flush?


478 名前: デフォルトの名無しさん  Mail: sage 投稿日: 2008/03/05(水) 23:56:25 
>>477
まさにおっしゃる通りでしたorz
的確なアドバイス助かりました m(_ _)m


f.flush() を追加するのでもいいけど、LOCK_UN を実行しないというのでもいいよね。

MS-DOS ならいざ知らず、最近の OS なら f.close() するときに「バッファの flush」と「ファイルの unlock」の両方をしてくれる。つまり OS が面倒見てくれるから、必要な後処理は OS に任せてしまいましょう、ということ。プログラマーが勝手に unlock して問題になるくらいなら、OS 任せにしたほうがいい。resource を管理するために OS があるんだから。

排他的ロックをしてるのに、1 プロセスより 2 プロセスのほうが速い?

ところで、<<476 のコードを改造して実験してみたとき、よくわからん現象に見舞われた。1 プロセスだと 1 分近くかかるのに、2 プロセスだと 15 秒で終わってしまうのだ。


コード (hoge.py):

#!/usr/bin/env python
N = 100000
filename = 'count-file'

from fcntl import flock, LOCK_EX, LOCK_UN
for i in xrange(N):
    f = open(filename, 'r+')
    flock(f.fileno(), LOCK_EX)
    s = f.readline()
    cnt = s and int(s) + 1 or 1
    f.seek(0)
    f.write(str(cnt))
    #flock(f.fileno(), LOCK_UN)
    f.close()


1 プロセスで実験:

$ echo 0 > count-file
$ time python hoge.py

real    0m52.042s
user    0m5.929s
sys     0m7.689s
$ cat count-file
100000


2 プロセスで実験:

$ echo 0 > count-file
$ time python hoge.py &
[1] 15324
$ time python hoge.py 

real    0m15.742s
user    0m3.983s
sys     0m5.387s
[1]+  Done                    time python hoge2.py

real    0m15.250s
user    0m7.940s
sys     0m10.725s
$ cat count-file
200000


1 プロセスだと 52 秒かかるのに、2 プロセスだと各々 15 秒で済んでいる。このスクリプトは処理を分散するタイプではなく、排他的にロックを獲得しないといけないから、プロセスが増える方が実行時間は増えるはずなのに、結果はまったく逆になった。

さっぱり意味がわからん。誰か原理を教えてください。
環境は MacOS X 10.4 Tiger, Intel CoreDuo 1.83GHz, Python 2.5.2 です。