有没有办法同时使用两只乌龟在一个窗口中同时画两个圆?我尝试了这段代码,但两只乌龟在分开的窗口中绘制
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()
但有人告诉我尝试多线程,但这段代码有一个严重的语义错误!!
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()
多处理或多线程的最佳建议是什么?
...我想要多线程或多处理答案,并且我坚持 就在上面。
如果我们小心地走钢丝,只有主线程发出turtle命令,turtle模块可以与线程一起使用:
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()
我们使用队列模块进行线程安全通信。
海龟真的有必要在不同的线程中吗?这个怎么办?
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)
我创建了一个
threaded_turtle
包,它利用queue.Queue
的功能无缝执行主线程中的所有海龟指令,而代码仍然像海龟在不同线程中运行一样编写。
threaded_turtle
在 GitLab 上:https://gitlab.com/zvone/threaded_turtle
使用该包,问题中的代码只需进行少量修改即可工作:
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
结果:
一次养8只海龟也没问题
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)
turtle模块不支持多线程。我认为你在这里唯一能做的就是其他人已经建议的:做一群乌龟。或者,您可以使用 mtTkinter 之类的东西,它与 tkinter 完全相同,但支持线程。
我认为 Beazley 宣扬的协程和生成器(第 447 页)在这里确实更符合逻辑:
注意:来自
deque
模块的 collections
也更可靠。
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()
这些答案都没有真正加快绘图速度,为了证明这一点,我进行了一个测试来比较它们:
import turtle
from time import time
import queue
import threading
start = time()
turtle.speed(0)
for i in range(360):
turtle.forward(1)
turtle.left(1)
for i in range(360):
turtle.forward(1)
turtle.right(1)
result1 = time()-start
start = time()
def tes1():
for i in range(360):
graphics.put(turtle1.forward)
graphics.put(turtle1.left)
def tes2():
for i in range(360):
graphics.put(turtle2.forward)
graphics.put(turtle2.right)
graphics = queue.Queue(1) # size = number of hardware threads you have - 1
turtle1 = turtle.Turtle('turtle')
turtle1.speed(0)
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(0)
thread2 = threading.Thread(target=tes2)
thread2.daemon = True # thread dies when main thread (only non-daemon thread) exits.
thread2.start()
while not graphics.empty():
(graphics.get())(1)
resutl2 = time()-start
print(f"time to draw without multithreading: {result1}\n\
time with multithreading: {resutl2}")
结果是多线程实际上更慢,在我的机器上我得到了这些结果: 不使用多线程绘制的时间:16.973097562789917 多线程时间:17.627304553985596