WxPythonを使って俺ついったークライアントを書く

Updated: Mon Nov 15 12:42:48 2010

スレッド

スレッドの使い方

子スレッドは、threading モジュールの Thread クラスで定義する。 スレッドが実行する関数を run() メソッドを上書き定義するサブクラスを定義すると良い。
CPython インタプリタのマルチスレッドは OS のカーネルスレッドを利用するにもかかわらず GIL (Giant Interpreter Lock) があるために Python コードを同時に実行できるスレッドは 1 つに限られる。 したがってマルチスレッドは並列性を持たす CPU 数に応じたスケーリング目的では使えないが、 メモリ空間を共有したままの並行処理には使え、またネットワークアクセスやディスクアクセスで GUI がブロックされてしまうことの対処に使える。

WxPython の場合はメインスレッドを GUI の処理に使い、時間のかかる処理をワーカースレッドに分割する。 ワーカースレッドからメインスレッドには PostEvent() 関数でイベントを送れるので、それをメインスレッドで適宜処理すればよい。

イベントのタイプを作成する wx.PyEventBinder クラスの __init__() メソッドの第 3 (expectedIDs) 引数は、 __call__() メソッドに渡すべき ID の数を指定する。0, 1, または 2 が有効。 __call__() メソッドは後方互換性のために存在するので新規のプログラムでは使用しない。 その場合は expectedIDs はデフォルト (0) にする。

サンプルプログラム

HTTP で画像を取得して表示するプログラム。 取得すべき URL をメインスレッドが Queue に入れ、 取得スレッドが Queue から取り出した URL を取得し、EVT_GOTURL イベントのパラメーターにしてメインスレッドに PostEvent() する。
メインスレッドは EVT_GOTURL イベントを受け取ると取得したデータを取りだして StaticBitmap としてフレーム imageFrame に追加する。
取得スレッドを setDaemon(True) でデーモンスレッドにすることで、 メインスレッドの終了時に取得スレッドの終了を待たずにプログアムを終了する。


import sys
from StringIO import StringIO
from urllib2 import urlopen, HTTPError, URLError
import wx
from threading import Thread
from Queue import Queue

EVT_TYPE_GOTURL = wx.NewEventType()
EVT_GOTURL = wx.PyEventBinder(EVT_TYPE_GOTURL)

class GotURLEvent(wx.PyCommandEvent):
    def __init__(self, etype, eid, value = None):
        wx.PyCommandEvent.__init__(self, etype, eid)
        self.value = value
    def GetValue(self):
        return self.value
                              
class GetterThread(Thread):
    def __init__(self, parent):
        Thread.__init__(self)
        self.in_queue = Queue()
        self.parent = parent
        self.setDaemon(True)
        self.start()
    def request(self, url):
        self.in_queue.put(url)
    def run(self):
        retry = 3
        while retry > 0:
            try:
                url = self.in_queue.get()
            except:
                retry -= 1
                continue
            rc, hdr, body = get_url(url)
            if rc == 0:
                evt = GotURLEvent(EVT_TYPE_GOTURL, wx.ID_ANY, body)
                wx.PostEvent(self.parent, evt)

def get_url(url):
    try:
        fd = urlopen(url)
        rc = 0
        hdr = fd.info().dict
        segments = []
        while True:
            seg = fd.read()
            if seg == '':
                break
            segments.append(seg)
        body = ''.join(segments)
        fd.close()
    except HTTPError, val:
        hdr = val.info().dict
        rc = val.code
        body = None
        print 'HTTPError', rc
    except URLError, val:
        rc = -2
        hdr = None
        body = val
        print 'URLError'
    return rc, hdr, body

class imageFrame(wx.Frame):
    def __init__(self, parent, imglist):
        wx.Frame.__init__(self, parent, size = (300, 600), title = 'image viewer')
        self.Bind(EVT_GOTURL, self.OnGotURL)
        self.getter = GetterThread(self)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.sizer)
        for filename in imglist:
            self.getter.request(filename)
    def OnGotURL(self, event):
        imgdata = event.GetValue()
        stream = StringIO(imgdata)
        image = wx.ImageFromStream(stream)
        stream.close()
        bitmap = image.ConvertToBitmap()
        self.sizer.Add(wx.StaticBitmap(self, wx.ID_ANY, bitmap), 0, 0)
        self.Layout()
        self.Refresh()

app = wx.App(False)
frame = imageFrame(None, sys.argv[1:])
frame.Show()
app.MainLoop()

参考

  1. 15.3 threading -- 高水準のスレッドインタフェース(Python 和訳ドキュメント ライブラリリファレンス)
  2. 5.10 Queue -- 同期キュークラス(Python 和訳ドキュメント ライブラリリファレンス)

  3. Type PyCommandEvent(New wxPyDocs)
  4. Type PyEventBinder(New wxPyDocs)
  5. wxPostEvent(Online wxDocs)

  6. LongRunningTasks(WxPyWiki)
  7. Non-Blocking Gui(WxPyWiki)
  8. wxPython and Threads(The Mouse Vs. The Python)
  9. wxPythonとthreading(None is None is None)
  10. wxPythonとthreadingで時間がかかる処理(None is None is None)
  11. wxPython: how to create a bash shell window?(eFreedom)

Gate, gate, lambda gate, lambda sam gate, bodhi svaha.
不許可無断複製
しょーた