Hatena::Groupbugrammer

蟲!虫!蟲!

Esehara Profile Site (by Heroku) / Github / bookable.jp (My Service)
過去の記事一覧はこちら

なにかあったら「えせはら あっと Gmail」まで送って頂ければ幸いです。
株式会社マリーチでは、Pythonやdjango、また自然言語処理を使ったお仕事を探しています

 | 

2011-12-02Python Advent Calender(全部俺):: 二日目

[]栗まんじゅう問題でまんじゅう怖い!! -- PythonにおけるThreadの実装 00:06

 アンサイクロペディアには、有名な「栗まんじゅう問題」というページがあります。

 栗まんじゅう問題 - アンサイクロペディア

  • のび太が1つしかない栗まんじゅうを食べようかどうか悩んでいる。
  • ドラえもんバイバインを栗まんじゅうにかける。栗まんじゅうは分裂を始める(5分ごとに2倍に、つまり5n分後には2のn乗倍になる)。
  • のび太はしばらく放置し、増えたところで食べようとするが、食べきれない。友人にも助けを求めるが分裂速度に追いつかない。
  • 栗まんじゅうは増え続け、のび太ドラえもんに泣きつく。
  • 困ったドラえもんは小型ロケットで宇宙空間に放出してしまう。

 さて、本編のドラえもんの漫画では、栗まんじゅうの恐怖が描かれています。この恐怖を、プログラミング的に味わうのもいいよね、と思ったので、今回はThreadを使ってその辺りの実装をやりたいなと思います。

Threadとは?

 いろんなところに書いてありますが、自分の理解だと「何かしらのプロセスを分割し、並行した処理の流れとして考えること」といったらいいのかな。例えば、一番簡単なところだと、入力待ちをしている間、次の処理が出来なくなります。例えば、メールソフトを考えた場合、メールの本文を書いている間も、新しいメールが来たらチェックして、ローカルに保存しておきたい、と思うわけです。その辺りを普通に実装しようとすると、処理が複雑になってしまいます。だから、あたかも並行に実行されているものとしてわけておき、入力処理は入力処理として、処理をとどめておき、なおかつ、新着メールの処理は一定期間に走らせよう、というわけです。

[入力待ち] ---> [入力待ちを一回打ちきる] ---> [メールのチェック] ---> [入力待ち] ---> [入力待ちを一回打ちきる] ---> [メールのチェック] 

:マルチスレッド:
---> [入力待ち] ------------------------------------------------------>

---> [メールのチェック] ---> [メールのチェック] ---> [メールのチェック] ...

 どっちのほうがわかりやすいかは一目瞭然ですね。

栗まんじゅうが自動的に作られるThreadを作る

 この仕組みを利用して、Pythonの対話コンソールで音を出せるような仕組みを作ったことがあります。

 Pythonのインタプリタを楽器にしてしまう簡単な方法。 - 蟲!虫!蟲! - #!/usr/bin/bugrammer

 これだと、ちょっとしたアプリにしまうので、もう少しミニマルアプリにしてみる。ここを参考に。

 threading – スレッドによる並列処理を管理する - Python Module of the Week

栗まんじゅう関数を作る

 まずは栗まんじゅう関数を作ってみましょう。

 普通に増やしても面白くはないので、あえてyieldでジェネレーターにしてみましょう。

def kuriman():
     kuriman = 1
     while 1:
        kuriman = kuriman * 2 if kuriman > 1 else 2
        yield kuriman

 returnを使わない理由としては、returnで値を返すと、そこで関数が一旦終了してしまうからです。そうすると、栗まんじゅうの個数を保有している変数であるkurimanを、外部スコープで保管しておかなくてはならなくなります。しかし、この変数は他で使うことが無い以上、一つの関数に閉じ込めておくほうがスッキリするので、yieldを使ったほうがいいのかなーというのが、採用理由です。このへんに関しては、別の日に書きたいと思います。ちなみに、yieldで値を返す関数それ自体は、単にジェネレーターオブジェクトを生成する関数となります。

>>> manju = kuriman()
>>> manju.next()
2
>>> manju.next()
4
>>> manju.next()
8
>>> manju.next()
16
>>> manju.next()
32

バイバインスレッドを作る

 次に、まんじゅうを増やしていく、バイバインスレッドの処理を作ってみましょう。

import time
def byby():
    manju = kuriman()
    while 1:
        print 
        print "()" * manju.next(),
        time.sleep(30)

 当然のことながら、無限に生成されていきますが、その間は処理が止まってしまいます。なので、これをスレッドにする必要があります。あと、プリント文にある「()」は栗まんじゅうのアスキーアート、ということにしておいてくださいね ;)。

import threading
t = threading.Thread(target = byby)
t.start()

 とっても簡単ですね。

注意

 しかし、このままでは、コンソール画面が栗まんじゅうに満たされてしまいます。なので、終了しないといけないように思うのですが、実はスレッドにはstart()はあっても、stop()というメソッドは無かったりします。

>>> dir(t)
['_Thread__args', '_Thread__block', '_Thread__bootstrap', '_Thread__bootstrap_inner', '_Thread__daemonic', '_Thread__delete', '_Thread__exc_clear', '_Thread__exc_info', '_Thread__ident', '_Thread__initialized', '_Thread__kwargs', '_Thread__name', '_Thread__started', '_Thread__stderr', '_Thread__stop', '_Thread__stopped', '_Thread__target', '_Verbose__verbose', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_block', '_note', '_reset_internal_locks', '_set_daemon', '_set_ident', 'daemon', 'getName', 'ident', 'isAlive', 'isDaemon', 'is_alive', 'join', 'name', 'run', 'setDaemon', 'setName', 'start']

 なので、例えば対話型コンソールでthreadを作っていて、「あれ、これ無限ループになるのでは。おかしくね?」ということに気がついたとき、あわてて終了しようとしても、プロセスが実行しつづけるので、Pythonのコンソール自体が終わらず、ただじっと増え続ける栗まんじゅうを見せされるはめになります。ドラえもんの栗まんじゅうと一緒ですね。

 ではどうするべきなのか?といえば、このときに使えるのがsetDaemonです。setDaemonメソッドは、メインスレッドが終了したときに、同時にサブスレッドも自動的に処理するということを可能にしてくれるスレッドです(ちなみに、このDaemonは、自分も勘違いしていたのですが、デーモン=悪魔ではなく、守護神のことらしいですね)。このことによって、Pythonのコンソールから、exit()を叩けば綺麗さっぱり消えてくれます。これは大切ですね。

t.setDaemon(True)

 ただ、注意しなければならないのは、join()のメソッドを使うと、子プロセスが終わるまで、そのスレッドは終了しなくなるので、注意が必要です。

 ちなみに、これを一つのコードとしてまとめると、下のようになります。

 栗まんじゅう ? GitHub

終わりに

 というわけで、今日はThreadの実装でした。しかし、これあと23日あるのか……

 ()()()()

 おや、こんなところに栗まんじゅうが……

RomuloRomulo2012/11/08 19:09A pleasingly rational awsner. Good to hear from you.

mvczzfmszcmvczzfmszc2012/11/09 10:344VEknc <a href="http://idgkraosqdxd.com/">idgkraosqdxd</a>

jzbcxprjzbcxpr2012/11/10 08:43G51ai9 , [url=http://wxkxtoibldmd.com/]wxkxtoibldmd[/url], [link=http://erqfokirvkzd.com/]erqfokirvkzd[/link], http://xhgpnrqztdnl.com/

qafgkvqafgkv2012/11/10 14:40IbOGvf <a href="http://uyzhdgfatief.com/">uyzhdgfatief</a>

 |