PHPでセッションの排他ロックを解除する

フォーラムのコメントにも目を通しましょうというお話。

排他ロック解除

session_start()について

Webを探してもあまり記事が拾えなかったので、放流しておく。

PHPでWebからAPIのモジュールを呼ぶシステムを作っていたら、モジュールの呼び出しが逐次処理になっていることが分かった。

そのシステムでは、セッションを使ってデータの読み書きをしている。
どうやらsession_start()を呼んだあと、モジュールの実行が終わるまで、セッションに排他ロックがかかってしまう模様。

PHPのセッション関連の調べ物をする時に、この辺りの話がでてこなかったので、今まで気付かなかった。

session_start()の説明を見ても、やっぱりそんなこと書いてない。
…と思っていたが、フォーラムのところに、まさにその話が出ていた。

dave1010 at gmail dot com 16-Dec-2010 05:35
PHP locks the session file until it is closed. If you have 2 scripts using the same session (i.e. from the same user) then the 2nd script will not finish its call to session_start() until the first script finishes execution.

If you have scripts that run for more than a second and users may be making more than 1 request at a time then it is worth calling session_write_close() as soon as you’ve finished writing session data.

<?php
// a lock is places on the session, so other scripts will have to wait
session_start();

// do all your writing to $_SESSION
$_SESSION[‘a’] = 1;

// $_SESSION can still be read, but writing will not update the session.
// the lock is removed and other scripts can now read the session
session_write_close();

do_something_slow();
?>

Found this out from http://konrness.com/php5/how-to-prevent-blocking-php-requests/

PHP: session_start – Manual

要約するとこんな感じか。

同じセッション(つまり同じユーザからの)を使用して、2つのスクリプトを呼ぶ場合、セッションの同時書き込みを回避するための排他ロックがかかる。最初のスクリプトが実行を終了するまで(排他ロックが解除されるまで)、2つ目のスクリプトは待ち状態になる。

複数のリクエストに対応するには、セッションデータを書き終えたすぐあとに、session_write_close()を呼ぶ必要がある。

つまり並列処理を実現するには、セッションの書き込みが終了した時点で、session_write_close()を呼ぶ。そこで排他ロックを解除すれば、続くリクエストが待ち状態になることなく実行される。

session_write_close()について

session_write_close()の説明には、その旨が書いてあった。

説明

void session_write_close ( void )

現在のセッションを終了し、セッションデータを書き込みます。

セッションデータは、 session_write_close() をコールしなくても、スクリプト終了時に保存されます。しかし、 セッションデータは、同時書き込みを防ぐためにロックされるため、 ある時点であるセッションの処理ができるスクリプトは、1つだけです。 セッションでフレームセットを使用する場合、 このロックのためにフレームがひとつずつロードされるような経験をするでしょう。 セッションへの全ての変更が行われるとすぐにセッションを終了することにより、 全てのフレームのロードに要する時間を減らすことができます。

PHP: session_write_close – Manual

う〜む…これはsession_start()のところにも書いておいてほしいものだ。
結構クリティカルな話だと思うんだけどなぁ。

というわけでセッション書き込み終了時点で、session_write_close()を呼ぶようにして、並列処理を実現することができた。
セッション読み書きしてる箇所が多かったので、修正にちと苦労したけど。

セッションを扱う時は、この事を考慮した実装をしないといけないな。
あとマニュアルの下のフォーラムにも目を通しておくこと。

参考

[PHP]セッションは排他ロックをす: n-streamからのお知らせ

セッションデータのロックと競合: FileMaker Pro 7~11 によるWeb開発覚え書き

プロになるための PHPプログラミング入門
星野 香保子
技術評論社
売り上げランキング: 16,049