5

メインスレッドで実行されている tkinter mainloop と別のスレッドで実行されているバックグラウンドプロセスによって tkinter ウィザードが自動的に更新されるように、スレッドを使用して python tkinter コードを作成しました。しかし、コードを実行するとしばらくするとpythonがクラッシュすることに気付きました。さらに、本質的にランダムですが、ほとんどの場合、python がクラッシュします。この問題を示す小さなテスト コードを作成しました (元のコードはこれに似ていますが、いくつかの実際のプロセスと他の多くの機能があるため、テスト コードを共有しています)。

######################################################################
 # Test Code for Tkinter with threads
import Tkinter
import threading
import Queue
import time

# Data Generator which will generate Data
def GenerateData(q):
    for i in range(1000000):
        #print "Generating Some Data, Iteration %s" %(i)
        time.sleep(0.01)
        q.put("Some Data from iteration %s. Putting this data in the queue for testing" %(i))

# Queue which will be used for storing Data
q = Queue.Queue()

def QueueHandler(widinst, q):
    linecount = 0
    while True:
        print "Running"
        if not q.empty():
            str = q.get()
            linecount = linecount + 1
            widinst.configure(state="normal")
            str = str + "\n"
            widinst.insert("end", str)
            if linecount > 100:
                widinst.delete('1.0', '2.0')
                linecount = linecount - 1
            widinst.see('end')
            widinst.configure(state="disabled")

# Create a thread and run GUI & QueueHadnler in it
tk = Tkinter.Tk()
scrollbar = Tkinter.Scrollbar(tk)
scrollbar.pack(side='right', fill='y' )
text_wid = Tkinter.Text(tk,yscrollcommand=scrollbar.set)
text_wid.pack()
t1 = threading.Thread(target=GenerateData, args=(q,))
t2 = threading.Thread(target=QueueHandler, args=(text_wid,q))
t2.start()
t1.start()

tk.mainloop()
######################################################################

再現するには:

このコードを IDLE で開いて実行すると、ハング状態に見えることがあります。ということで再現するためにスリープ時間を0.01から0.1に変更して実行。この後、アプリケーションを停止し、0.01 に戻して、保存して実行します。今回は実行され、しばらくすると python が動作しなくなります。Windows7(64ビット)を使用しています。

質問

私はそれをpython bugsに提出しましたが、拒否されました。しかし、スタックオーバーフローの質問の1つから、tkinterでの書き込みにキューを使用するというアイデアを得ました。それを処理するために何をすべきかを提案してください。

編集されたコード:

# Test Code for Tkinter with threads
import Tkinter
import threading
import Queue
import time

# Data Generator which will generate Data
def GenerateData(q):
    for i in range(1000000):
        #print "Generating Some Data, Iteration %s" %(i)
        time.sleep(0)
        q.put("Some Data from iteration %s. Putting this data in the queue for testing" %(i))

# Queue which will be used for storing Data
q = Queue.Queue()

def QueueHandler():
    global widinst, q
    linecount = 0
    if not q.empty():
        str = q.get()
        linecount = linecount + 1
        widinst.configure(state="normal")
        str = str + "\n"
        widinst.insert("end", str)
        if linecount > 100:
            widinst.delete('1.0', '2.0')
            linecount = linecount - 1
        widinst.see('end')
        widinst.configure(state="disabled")
        tk.after(1,QueueHandler)

# Create a thread and run GUI & QueueHadnler in it
tk = Tkinter.Tk()
scrollbar = Tkinter.Scrollbar(tk)
scrollbar.pack(side='right', fill='y' )
text_wid = Tkinter.Text(tk,yscrollcommand=scrollbar.set)
text_wid.pack()
t1 = threading.Thread(target=GenerateData, args=(q,))
#t2 = threading.Thread(target=QueueHandler, args=(text_wid,q))
#t2.start()
widinst = text_wid
t1.start()
tk.after(1,QueueHandler)
tk.mainloop()
4

3 に答える 3

7

Tkinter はスレッドセーフではありません。メインスレッド以外からは Tkinter ウィジェットにアクセスできません。QueueHandlerメイン スレッドで実行されるように、コードをリファクタリングする必要があります。

于 2013-01-05T14:13:02.463 に答える
3

ブライアンが言うように、Tkinterはスレッドセーフではありません。これを実現しようとする変更は次のとおりです:http://tkinter.unpythonic.net/wiki/mtTkinter

于 2013-01-05T19:44:44.293 に答える
1

Tkinterはスレッドセーフになるように設計されていますが、 2.x3.xの両方でバグによるものではありません。

修正プログラムがリリースされるまで (および古いバージョンで)、mtTkinter回避策として (ドロップイン置換として設計されている) を使用する必要があります。

于 2018-04-14T10:37:44.367 に答える