我在Mac OS X(10.7和10.8)上运行python(2.7)Tkinter GUI应用程序。 UI处于一个单独的进程中,该进程使用多处理从主脚本分离出来。然而,当我跑步时,它失败了:
'The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec(). Break on THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY_YOU_MUST_EXEC__() to debug.'
这适用于Windows。
我发现了一个与python相关的错误:http://bugs.python.org/issue8713 但遗憾的是,看起来修复版仅在3.x版本中实现,但我也需要支持2.7。
我知道有关于同一错误的其他一些SO问题,例如:Python multiprocessing bug on Mac OS X
但是我无法弄清楚在我的特定情况下究竟会解决什么问题。
有关如何在Mac上使用它的任何想法吗?
代码如下。创建DriverVisualizer()(在另一个脚本中),初始化另一个进程的UI。
from util import *
from multiprocessing import Process, Pipe
from Tkinter import *
import threading
import Queue
from time import *
class VisualizerUI:
def __init__(self, conn, count, pixelSize):
self._conn = conn
self._master = Tk()
self._q = Queue.Queue()
self._count = count
self._values = []
self._leds = []
self._pixelSize = pixelSize
self._pixelPad = int(pixelSize / 2)
self._pixelSpace = 4
#init colors to all black (off)
for i in range(self._count):
self._values.append("#000000")
self.initUI()
self._thread = threading.Thread(target=self.commThread).start()
def mainloop(self):
self._master.mainloop()
try:
self._conn.send({"status" : False})
except:
pass
def updateUI(self):
try:
for i in range(self._count):
self._canvas.itemconfig(self._leds[i], fill=self._values[i])
except TclError:
#Looks like the UI closed!
pass
def commThread(self):
data = None
error = False
while True:
#bit of a hack, but need to check occasionaly for window size change
if self._width != self._master.winfo_width() or self._height != self._master.winfo_height():
self._width = self._master.winfo_width()
self._height = self._master.winfo_height()
self._master.after_idle(self.layoutPixels)
try:
data = self._conn.recv()
except EOFError:
error = True
break
if data["run"]:
self._values = data["data"]
self.updateUI()
self._conn.send({"status" : True})
else:
break
if not error:
self._conn.send("Killing UI...")
self._master.destroy()
def layoutPixels(self):
self._canvas.config(width=self._width, height=self._height)
newRow = True
x_off = self._pixelPad
y_off = self._pixelPad
for i in range(self._count):
if (x_off + (self._pixelSize * 2) + self._pixelSpace + self._pixelPad) > self._width:
newRow = True
y_off = y_off + self._pixelPad + self._pixelSize
if newRow:
x_off = self._pixelPad
newRow = False
else:
x_off = x_off + self._pixelSize + self._pixelSpace
self._canvas.coords(self._leds[i], x_off, y_off, x_off + self._pixelSize, y_off + self._pixelSize)
y = (y_off + self._pixelSize + self._pixelPad)
if self._height != y:
self._master.geometry("{0}x{1}".format(self._width, y))
self._master.update()
def __CancelCommand(event=None):
pass
def initUI(self):
m = self._master
m.protocol('WM_DELETE_WINDOW', self.__CancelCommand)
m.title("LED Strip Visualizer")
m.geometry("1400x50")
m.update()
self._width = m.winfo_width()
self._height = m.winfo_height()
m.minsize(self._width, self._height)
self._canvas = Canvas(self._master, background="#000000")
c = self._canvas
c.pack(side=TOP)
for i in range(self._count):
index = c.create_oval(0,0,self._pixelSize,self._pixelSize, fill=self._values[i])
self._leds.append(index)
#m.bind("<Configure>", self.resize)
self.layoutPixels()
def toHexColor(r,g,b):
return "#{0:02x}{1:02x}{2:02x}".format(r,g,b)
def startUI(conn, count, pixelSize):
ui = VisualizerUI(conn, count, pixelSize)
ui.mainloop()
class DriverVisualizer(object):
"""Main driver for Visualizer UI (for testing)"""
def __init__(self, leds, pixelSize = 15, showCurrent = False):
self.leds = leds
self._showCurrent = showCurrent
if self._showCurrent:
self._peakCurrent = 0;
else:
self._peakCurrent = None
self._parent_conn, self._child_conn = Pipe()
p = Process(target=startUI, args=(self._child_conn, self.leds, pixelSize))
p.start()
sleep(0.5) # give the UI some time to spin up before throwing data at it
def __del__(self):
self._parent_conn.send({"data" : None, "run" : False})
print self._parent_conn.recv()
def calcCurrent(self, data):
c = 0
for r, g, b in data:
c = c + int(((r/255.0) * 20.0) + ((g/255.0) * 20.0) + ((b/255.0) * 20.0))
if c > self._peakCurrent:
self._peakCurrent = c
return c
#Push new data to strand
def update(self, data):
c = None
if self._showCurrent:
c = self.calcCurrent(data)
self._parent_conn.send({"data" : [toHexColor(*(data[x])) for x in range(self.leds)], "run" : True, "c" : c, "peak" : self._peakCurrent})
resp = self._parent_conn.recv()
if not resp["status"]:
error = True
parent_conn.close()
答案 0 :(得分:1)
我遇到同样的问题,请检查一下:
https://stackoverflow.com/a/19082049/1956309
这会让你跟踪一个Tkinter错误:
http://bugs.python.org/issue5527#msg195480
为我做的技巧(Mac OS 10.8 with Python 2.7)的解决方案是重新排列代码,以便&#34;导入Tkinter&#34;在您调用任何类型的process.start()
之后放置看起来像:
import multiprocessing
def cam_loop(the_q):
while True:
the_q.put('foo in the queue')
def show_loop(the_q):
while True:
from_queue = the_q.get()
print from_queue
if __name__ == '__main__':
try:
the_q = multiprocessing.Queue(1)
cam_process = multiprocessing.Process(target=cam_loop,args=(the_q, ))
cam_process.start()
show_process = multiprocessing.Process(target=show_loop,args=(the_q, ))
show_process.start()
import Tkinter as tk # << Here!
cam_process.join()
show_loop.join()
except KeyboardInterrupt:
cam_process.terminate()
show_process.terminate()
P.d:感谢JW Lim向我展示礼貌!