문제

world! In turtle graphics in python, there's possible to create various Turtle objects and manipulate them with their methods, forward, backward... I wanted to experiment with threads so I wrote a threaded class called MyTurtleManipulator.

from threading import Thread
from cTurtle import Turtle 
import random

class MyTurtleManipulator(Thread):
  def __init__(self, turtle):
    Thread.__init__(self)
    self.turtle=turtle
  def run(self):
    actions=[Turtle.forward, Turtle.right, Turtle.left]    
    while True:      
      action=random.choice(actions)      
      action(self.turtle, random.randint(1,25))

turtles=[Turtle() for i in range(5)]
threads=[MyTurtleManipulator(turtle) for turtle in turtles]

for thread in threads:
  print(thread)
  thread.start()

With the experiment I expected to see all the turtles moving "simultaneously" and randomly but When I run the program i get these errors:

<MyTurtleManipulator(Thread-1, initial)>
<MyTurtleManipulator(Thread-2, initial)>
<MyTurtleManipulator(Thread-3, initial)>
<MyTurtleManipulator(Thread-4, initial)>
<MyTurtleManipulator(Thread-5, initial)>
>>> Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
    self.run()
  File "/home/rfrm/test.py", line 13, in run
    action(self.turtle, random.randint(1,25))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1162, in forward
    checkargs((int, float))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1131, in _go
    ende = self._position + self._orient * distance
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2266, in _goto
    (start, self._position),
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 419, in _drawline
    cl.append(-y)
  File "<string>", line 1, in coords
  File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
    self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
    self.run()
  File "/home/rfrm/test.py", line 13, in run
    action(self.turtle, random.randint(1,25))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1203, in right
    checkargs((int, float))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2300, in _rotate
    self._orient = self._orient.rotate(delta)
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2085, in _update
    for t in screen._turtles:
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2219, in _drawturtle
    screen._drawpoly(titem, shape, fill=fc, outline=oc,
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 384, in _drawpoly
    cl.append(-y)
  File "<string>", line 1, in coords
  File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
    self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop

Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
    self.run()
  File "/home/rfrm/test.py", line 13, in run
    action(self.turtle, random.randint(1,25))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1162, in forward
    checkargs((int, float))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1131, in _go
    ende = self._position + self._orient * distance
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2270, in _goto
    screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 419, in _drawline
    cl.append(-y)
  File "<string>", line 1, in coords
  File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
    self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop

Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
    self.run()
  File "/home/rfrm/test.py", line 13, in run
    action(self.turtle, random.randint(1,25))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1162, in forward
    checkargs((int, float))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1131, in _go
    ende = self._position + self._orient * distance
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2270, in _goto
    screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 419, in _drawline
    cl.append(-y)
  File "<string>", line 1, in coords
  File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
    self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop

Exception in thread Thread-5:
Traceback (most recent call last):
  File "/usr/lib/python3.1/threading.py", line 516, in _bootstrap_inner
    self.run()
  File "/home/rfrm/test.py", line 13, in run
    action(self.turtle, random.randint(1,25))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 1203, in right
    checkargs((int, float))
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2300, in _rotate
    self._orient = self._orient.rotate(delta)
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2085, in _update
    for t in screen._turtles:
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 2219, in _drawturtle
    screen._drawpoly(titem, shape, fill=fc, outline=oc,
  File "/usr/local/lib/python3.1/dist-packages/cTurtle.py", line 384, in _drawpoly
    cl.append(-y)
  File "<string>", line 1, in coords
  File "/usr/lib/python3.1/tkinter/__init__.py", line 2123, in coords
    self.tk.call((self._w, 'coords') + args)))
RuntimeError: main thread is not in main loop

What does this means, what does "main thread is not in main loop" means. Thank you for your help.

도움이 되었습니까?

해결책

this seems to be a python/tkinter limitation as described here, turtle and threads are not friends

다른 팁

This has its limitations but may still be possible. The answer is in your error messges:

RuntimeError: main thread is not in main loop

Limit your turtle/tkinter operations to the main thread. In my rework of your example below, I've used the thread safe queue data structure to communicate between the threads and turtle:

from threading import Thread, active_count
from turtle import Turtle, Screen
import queue
import random

QUEUE_SIZE = 1  # set higher the more hardware threads you have
ACTIONS = [Turtle.forward, Turtle.right, Turtle.left]
COLORS = ['red', 'black', 'blue', 'green', 'magenta']

class MyTurtleManipulator(Thread):

    def __init__(self, turtle):
        super().__init__()
        self.turtle = turtle

    def run(self):
        for _ in range(100):
            actions.put((self.turtle, random.choice(ACTIONS), random.randint(1, 30)))

def process_queue():
    while not actions.empty():
        turtle, action, argument = actions.get()
        action(turtle, argument)

    if active_count() > 1:
        screen.ontimer(process_queue, 100)

actions = queue.Queue(QUEUE_SIZE)

for color in COLORS:
    turtle = Turtle('turtle')
    turtle.color(color)
    turtle.setheading(random.randint(0, 360))
    MyTurtleManipulator(turtle).start()

screen = Screen()

process_queue()

screen.mainloop()

I set the QUEUE_SIZE to 1 as I'm on a machine with only two threads! I'm curious to know if everything works correctly on a machine with more threads and a QUEUE_SIZE ~= #threads - 1

enter image description here

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top