Wizard In The Market
システムトレードの魔術師

*

絶対ダメ! マルチスレッドでの共通変数のインクリメント演算

公開日: : Python , , , , , ,

Hack de Overheid - Apps voor Amsterdam

Photo by Sebastiaan ter Burg

デバッグ中の発見

とあるマルチスレッドプログラムをPythonで書いていた際に遭遇した誤使用です。C/C++等の言語を使った場合には起こらない仕様なので、知っておくと役立つ時がくるはずです。これはPythonだけでなく、Rubyでも同様のことが起こるので、Rubyistさんも是非気をつけていただければと思います。

@ahaha_traderさんのご指摘により、C/C++でも同様のことが発生することを教えていただきました・・・。不勉強をお詫び申し上げます。

このブログを見ているような方々だとバグが生じる実際のコードと、結果をまずお見せしたほうが良いと思うので、サンプル用に作ったコードがこちらです。

バグが生じるソースコード

やっている内容は、12個のスレッドを使って self.increment_count + 1 を12,000回繰り返すという単純処理です。

実行結果

本来、12*1,000の12,000を表示させたかったはずのこのコードなのですが、残念ながら29の違いが生じています。なぜこれが生じてしまうのでしょうか。

動作不良の理由

C/C++など、正式なインクリメントが適応されているような言語ですと、マルチスレッドで行っても、確実にプロセッサレベルで正確にインクリメント処理が行われるので問題がありません。

ですが、PythonやRubyのインクリメント処理は、C/C++で使用されるようなインクリメント処理とはまったく異なります。PythonやRubyの場合のインクリメントの記述自体は、インクリメントっぽく書かれていますが、実際に行われているのは以下の処理です。

ということは、increment_count + 1 の演算が行われた後の結果のPython/Rubyオブジェクトにincrement_countの参照が適応されます。簡単に言うと、演算と結果の格納が2つの処理になってしまっているのです。

この場合、マルチスレッドにて、increment_count + 1 の演算がポインタの割り当てより前に他のスレッドにて同時に行われてしまうというケースが生じます。それが、今回の検証の場合 29/12,000 の割合で生じてしまっていたのですね。

参考URL

誤使用の回避方法

回避する方法は、Queue.Queueクラスを使い、putされた個数を取得するという方法が簡単で便利です(12,000回もカウントするのには実用的ではないけれど)。他にもthreading.Lockを使う方法もありますが、マルチスレッドの利点が減ってしまうかもですね。

なかなかデバッグしにくい内容で手こずりましたが、バグの原因が特定できると納得の行く結果となりました。みなさんもお気をつけ下さいね!

にほんブログ村 為替ブログへ 
Fx-Kirin

About Fx-Kirin

2009年10月にFXを開始、翌年2010年5月から脱サラをしてFX業界に専念。 2012年10月頃から本格的に勝ち始め、一月で資産を倍にする、2年半月間負けなし等、安定した収支で2013年11月に生涯FX収支が1億を超える。 投資スタイルはシステムトレード。プログラミングの知識がほぼない状態から、独学で自分がしたいと思うことであればほぼ実現することが可能なレベルまで成長。好きな言語はRuby, Python。必要となればC++からVBA、Pascal等なんでも行う。MT4/MT5のプログラミングも得意。 2011年にはFXで稼いだ資金をもとにシンガポールに移住し、留学も兼ねて起業をチャレンジするほど、ビジネスを興すことに熱意がある。国内の業者を主に使い始めたことから、2012年に帰国。零細株式会社経営中。

Adsense

  • このエントリーをはてなブックマークに追加
  • Pocket
  • 64 follow us in feedly

関連記事

Python 2, Python 3 で string を bytes に変換する。

共通の処理系にしておきたかったので、メモ書き。 [bm url="https://python-future.or

記事を読む

Python x64 & MinGW64 環境の構築

流石に詰まりまくったのでまとめることにする。 MSYS2 をインストール 個人的にこれからメインで使いたいと思っ

記事を読む

Pythonのsocketでプロセス間通信をして価格データ等を送信する

どうも、お久しぶりです。キリンです。 取り敢えず1ヶ月ほど、連続でブログの更新を続けてみたのですが、そ

記事を読む

Python2 から Python3 へのC Extension の移行

最初に追加 モジュールの初期化と状態情報を書き換える initmyextension 関数などの初期状態の関

記事を読む

Call Python/Numpy Function within Metatrader 4

Github Link [bm url="https://github.com/fx-kirin/mt4-nump

記事を読む

話題のクローラー・スクレイピング!PythonならScrapyが超優秀な件

Rubyの読書会に行ったら、Pythonの面白いお話を聞けたというお話です。 Rubyクローラー本の読書会に参

記事を読む

no image

vim-ipythonをWindows 7 x64で使うとR6034 が出る件

個人的なただの忘備録。 Visual Studioのコマンドプロンプトから実行すること。 http://st

記事を読む

DictCursor に AttrDict を指定する

記事を読む

ipdb だけではなく IPython.embed も使おう

ipdb だと複数行の挿入ができなかったりするが、その問題が解消される。明らかにこちらのほうが使い勝手がいい。行のデ

記事を読む

no image

JAVA の SHA1 Digestの作り方

>>> import base64 >>> import hashlib >>> base64.b64encode(

記事を読む

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Adsense

DictCursor に AttrDict を指定する

Python requests に DefaultTimeout を設定する

Pythonコード 参考リンク [bm url="https://stackoverflow

Python Mock で オリジナルのインスタンメソッドのを呼びたい時

autospec と sideeffect を組み合わせるのが解決策だった。

Python 2, Python 3 で string を bytes に変換する。

共通の処理系にしておきたかったので、メモ書き。 [bm url="https://python

ctypes で c_char array を c_char_p に変換する

なかなか情報がなかったのでメモ書き。

→もっと見る

PAGE TOP ↑