问题
Is there a way to use two turtles at the same time to draw two circles at the same time in one window? I tried this code but two turtles draw in separated windows
from multiprocessing import Process
import turtle
t1=turtle.Turtle()
t2=turtle.Turtle()
def tes1():
t1.speed(0)
i=0
while i < 360:
t1.forward(1)
t1.left(1)
i+=1
def tes2():
t2.speed(0)
i=0
while i < 360:
t2.forward(1)
t2.right(1)
i+=1
if __name__ == '__main__':
p1 = Process(target=tes1)
p1.start()
p2 = Process(target=tes2)
p2.start()
p1.join()
p2.join()
but somebody told me try multithreading but this code has a bad semantic error!!
import threading
import turtle
t1=turtle.Turtle()
t2=turtle.Turtle()
def tes1():
t1.speed(0)
i=0
while i < 360:
t1.forward(1)
t1.left(1)
i+=1
def tes2():
t2.speed(0)
i=0
while i < 360:
t2.forward(1)
t2.right(1)
i+=1
t = threading.Thread(target=tes1)
t.daemon = True # thread dies when main thread (only non-daemon thread) exits.
t.start()
t3 = threading.Thread(target=tes2)
t3.daemon = True # thread dies when main thread (only non-daemon thread) exits.
t3.start()
And what is the best suggestion multiprocessing or multithreading?
回答1:
Is it really necessary that the turtles are in different threads? What about this?
import turtle
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t1.speed(0)
t2.speed(0)
for i in range(360):
t1.forward(1)
t1.left(1)
t2.forward(1)
t2.right(1)
回答2:
... I want multithreading or multiprocessing answer and I'm insisting on it.
The turtle module can be used with threading if we carefully walk a tightrope where only the main thread issues turtle commands:
import queue
import threading
import turtle
def tes1():
for _ in range(360):
graphics.put(turtle1.forward)
graphics.put(turtle1.left)
def tes2():
for _ in range(360):
graphics.put(turtle2.forward)
graphics.put(turtle2.right)
def process_queue():
while not graphics.empty():
(graphics.get())(1)
if threading.active_count() > 1:
turtle.ontimer(process_queue, 100)
graphics = queue.Queue(1) # size = number of hardware threads you have - 1
turtle1 = turtle.Turtle('turtle')
turtle1.speed('fastest')
thread1 = threading.Thread(target=tes1)
thread1.daemon = True # thread dies when main thread (only non-daemon thread) exits.
thread1.start()
turtle2 = turtle.Turtle('turtle')
turtle2.speed('fastest')
thread2 = threading.Thread(target=tes2)
thread2.daemon = True # thread dies when main thread (only non-daemon thread) exits.
thread2.start()
process_queue()
turtle.exitonclick()
We're using the queue module for thread-safe communications.
回答3:
8 turtles at a time is no problem either
import turtle
turtle.delay(0)
t = [turtle.Turtle() for i in range(8)]
for i, j in enumerate(t):
j.right(i*45)
j.speed(0)
for i in range(360):
for j in t:
j.forward(1)
j.right(1)
回答4:
The turtle module does not support multithreading. I think the only thing you can do here is what others have already suggested: Make a bunch of turtles. Alternatively, you could use something like mtTkinter, which is exactly like tkinter, but supports threading.
回答5:
I've created a threaded_turtle
package, which utilises functionality of queue.Queue
to seamlessly execute all turtle instructions in the main thread, while the code is still written as if the turtles were running in different threads.
threaded_turtle
is on GitLab: https://gitlab.com/zvone/threaded_turtle
With that package, the code from the question needs only minor modifications to work:
import turtle
from threaded_turtle import ThreadSerializer, TurtleThread
ctrl = ThreadSerializer() ## <-- create a serializer
t1=turtle.Turtle()
t2=turtle.Turtle()
def tes1(t1): ## <-- additional argument
t1.speed(0)
i=0
while i < 360:
t1.forward(1)
t1.left(1)
i+=1
def tes2(t2): ## <-- additional argument
t2.speed(0)
i=0
while i < 360:
t2.forward(1)
t2.right(1)
i+=1
t = TurtleThread(ctrl, t1, target=tes1) ## <-- additional arguments
t.daemon = True
t.start()
t3 = TurtleThread(ctrl, t2, target=tes2) ## <-- additional arguments
t3.daemon = True
t3.start()
ctrl.run_forever(1) ## <-- run the serializer
The result:
回答6:
I think the coroutines and generators that Beazley preaches (on p. 447) are really more logical here:
Note: the deque
from the collections
module is more reliable too.
import turtle
from collections import deque
def move1():
for _ in range(360):
turtle1.forward(1)
turtle1.left(1)
yield
def move2():
for _ in range(360):
turtle2.forward(1)
turtle2.right(1)
yield
# Create turtles
turtle1 = turtle.Turtle('turtle')
turtle1.speed('fastest')
turtle2 = turtle.Turtle('turtle')
turtle2.speed('fastest')
# Create and populate a task queue
taskqueue = deque()
taskqueue.append(move1()) # Add tasks (generators)
taskqueue.append(move2())
while taskqueue: # Run all of the tasks
# Get the next task
task = taskqueue.pop()
try:
# Run it to the next yield and enqueue
next(task)
taskqueue.appendleft(task)
except StopIteration:
# Task is done
pass
turtle.done()
来源:https://stackoverflow.com/questions/19498447/multithreading-with-python-turtle