为什么我不能同时运行两个以上的线程?

时间:2018-04-08 22:15:06

标签: python multithreading turtle-graphics

我是线程新手,所以如果我遗漏了一些完全明显的东西,请原谅。

这是我的代码(海龟竞赛):

(跳到线程部分代码的底部)

import turtle
from random import randint
import threading


n = turtle.Turtle()
n.speed(10)
n.hideturtle()
n.penup()
n.goto(-600, 300)
n.pendown()

for x in range(1, 51):
    n.forward(12)
    n.write(x)
    n.forward(12)

n.right(90)
n.forward(270)
n.right(90)
n.forward(1200)
n.right(90)
n.forward(270)
n.right(180)
n.forward(15)
n.left(90)

for x in range(0, 4):
    n.forward(1200)
    n.right(90)
    n.forward(30)
    n.right(90)
    n.forward(1200)
    n.left(90)
    n.forward(30)
    n.left(90)

n.forward(1200)
n.right(90)

red = turtle.Turtle()
blue = turtle.Turtle()
green = turtle.Turtle()
orange = turtle.Turtle()
brown = turtle.Turtle()
black = turtle.Turtle()
pink = turtle.Turtle()
purple = turtle.Turtle()

turtles = {
    red: ['red', 270],
    blue: ['blue', 240],
    green: ['green', 210],
    orange: ['orange', 180],
    brown: ['brown', 150],
    black: ['black', 120],
    pink: ['pink', 90],
    purple: ['purple', 60]
}

for x in turtles:
    x.color(turtles[x][0])
    x.shape('turtle')
    x.penup()
    x.goto(-600, turtles[x][1])


def move_red(num1, num2):
    for y in range(0, 240):
        red.speed(randint(num1, num2))
        red.forward(5)
    return

def move_blue(num1, num2):
    for y in range(0, 240):
        blue.speed(randint(num1, num2))
        blue.forward(5)
    return

def move_green(num1, num2):
    for y in range(0, 240):
        green.speed(randint(num1, num2))
        green.forward(5)
    return

def move_orange(num1, num2):
    for y in range(0, 240):
        orange.speed(randint(num1, num2))
        orange.forward(5)
    return

def move_brown(num1, num2):
    for y in range(0, 240):
        brown.speed(randint(num1, num2))
        brown.forward(5)
    return

def move_black(num1, num2):
    for y in range(0, 240):
        black.speed(randint(num1, num2))
        black.forward(5)
    return

def move_pink(num1, num2):
    for y in range(0, 240):
        pink.speed(randint(num1, num2))
        pink.forward(5)
    return

def move_purple(num1, num2):
    for y in range(0, 240):
        purple.speed(randint(num1, num2))
        purple.forward(5)
    return

t1 = threading.Thread(target = move_red, args = [1, 10])
t2 = threading.Thread(target = move_blue, args = [1, 10])
t3 = threading.Thread(target = move_green, args = [1, 10])
t4 = threading.Thread(target = move_orange, args = [1, 10])
t5 = threading.Thread(target = move_brown, args = [1, 10])
t6 = threading.Thread(target = move_black, args = [1, 10])
t7 = threading.Thread(target = move_pink, args = [1, 10])
t8 = threading.Thread(target = move_purple, args = [1, 10])

ts = [t1, t2, t3, t4, t5, t6, t7, t8]
for x in ts:
    x.start()

turtle.done()

如果你在编辑器中运行它,你会看到乌龟随机停留。当我运行2个线程时,这不会发生。 .join()也无济于事。请向我解释为什么线程不起作用。

2 个答案:

答案 0 :(得分:0)

这可以完成,但您需要限制调用tkinter到主线程的乌龟操作。下面是我的拆解和重建您的程序以这种方式工作并删除冗余。 (我离开了你可以添加回来的背景图。)我使用线程安全队列数据结构来在线程和tkinter之间进行通信:

from threading import Thread, active_count
from turtle import Turtle, Screen
from random import randint
from queue import Queue  # use for thread-safe communications

QUEUE_SIZE = 1  # set higher the more unused hardware threads you have
COLORS = ['red', 'blue', 'green', 'orange', 'brown', 'black', 'pink', 'purple']

def move_turtle(turtle):
    for _ in range(240):
        actions.put((turtle.forward, randint(1, 10)))

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

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

actions = Queue(QUEUE_SIZE)

screen = Screen()
screen.setup(1200, 600)

threads = []

for y, color in enumerate(COLORS):
    turtle = Turtle('turtle', visible=False)
    turtle.color(color)
    turtle.speed('fastest')
    turtle.penup()
    turtle.goto(-600, 270 - y * 30)
    turtle.showturtle()

    thread = Thread(target=move_turtle, args=[turtle])
    threads.append(thread)

for thread in threads:
    thread.start()

process_queue()

screen.mainloop()

enter image description here

  

我不希望海龟向前移动;我想要它们   以不同的速度向前移动相同的距离

您可以使用我设置的环境执行此操作:

def move_turtle(turtle):
    for _ in range(240):
        actions.put((turtle.speed, randint(1, 10)))
        actions.put((turtle.forward, 5))

但是turtle.speed()是关于绘制速度而你只是(不)绘制一条五像素线,因此绘制速度差别不大。在比赛的中间,这就是正在发生的事情:

enter image description here

即使在比赛开始之前将海龟设置为随机速度,而不是改变它们,也没有区别。我认为改变前进距离会带来更激动人心的比赛。

答案 1 :(得分:0)

我创建了一个名为height的库,它使用与@cdlane在答案中提供的方法相同的方法,但在幕后进行“智能”工作。

你在gitlab上找到了这个库:https://gitlab.com/zvone/threaded_turtle

以下是与问题中相同的代码,经过修改后可与mat-row库配合使用:

threaded_turtle

但是,代码可以变得更简单。我会做这样的事情:

threaded_turtle

另请注意,我使用的是import turtle from random import randint from threaded_turtle import ThreadSerializer, TurtleThread n = turtle.Turtle() n.speed(10) n.hideturtle() n.penup() n.goto(-600, 300) n.pendown() for x in range(1, 51): n.forward(12) n.write(x) n.forward(12) n.right(90) n.forward(270) n.right(90) n.forward(1200) n.right(90) n.forward(270) n.right(180) n.forward(15) n.left(90) for x in range(0, 4): n.forward(1200) n.right(90) n.forward(30) n.right(90) n.forward(1200) n.left(90) n.forward(30) n.left(90) n.forward(1200) n.right(90) red = turtle.Turtle() blue = turtle.Turtle() green = turtle.Turtle() orange = turtle.Turtle() brown = turtle.Turtle() black = turtle.Turtle() pink = turtle.Turtle() purple = turtle.Turtle() turtles = { red: ['red', 270], blue: ['blue', 240], green: ['green', 210], orange: ['orange', 180], brown: ['brown', 150], black: ['black', 120], pink: ['pink', 90], purple: ['purple', 60] } for x in turtles: x.color(turtles[x][0]) x.shape('turtle') x.penup() x.goto(-600, turtles[x][1]) def move_red(red, num1, num2): for y in range(0, 240): red.speed(randint(num1, num2)) red.forward(5) return def move_blue(blue, num1, num2): for y in range(0, 240): blue.speed(randint(num1, num2)) blue.forward(5) return def move_green(green, num1, num2): for y in range(0, 240): green.speed(randint(num1, num2)) green.forward(5) return def move_orange(orange, num1, num2): for y in range(0, 240): orange.speed(randint(num1, num2)) orange.forward(5) return def move_brown(brown, num1, num2): for y in range(0, 240): brown.speed(randint(num1, num2)) brown.forward(5) return def move_black(black, num1, num2): for y in range(0, 240): black.speed(randint(num1, num2)) black.forward(5) return def move_pink(pink, num1, num2): for y in range(0, 240): pink.speed(randint(num1, num2)) pink.forward(5) return def move_purple(purple, num1, num2): for y in range(0, 240): purple.speed(randint(num1, num2)) purple.forward(5) return ctrl = ThreadSerializer() t1 = TurtleThread(ctrl, red, target=move_red, args=[1, 10]) t2 = TurtleThread(ctrl, blue, target=move_blue, args=[1, 10]) t3 = TurtleThread(ctrl, green, target=move_green, args=[1, 10]) t4 = TurtleThread(ctrl, orange, target=move_orange, args=[1, 10]) t5 = TurtleThread(ctrl, brown, target=move_brown, args=[1, 10]) t6 = TurtleThread(ctrl, black, target=move_black, args=[1, 10]) t7 = TurtleThread(ctrl, pink, target=move_pink, args=[1, 10]) t8 = TurtleThread(ctrl, purple, target=move_purple, args=[1, 10]) ts = [t1, t2, t3, t4, t5, t6, t7, t8] for x in ts: x.start() ctrl.run_forever() ,而不是import turtle import time from random import randint from threaded_turtle import ThreadSerializer, TurtleThread def draw_background(): n = turtle.Turtle() n.speed(10) n.hideturtle() n.penup() n.goto(-600, 300) n.pendown() for x in range(1, 51): n.forward(12) n.write(x) n.forward(12) n.right(90) n.forward(270) n.right(90) n.forward(1200) n.right(90) n.forward(270) n.right(180) n.forward(15) n.left(90) for x in range(0, 4): n.forward(1200) n.right(90) n.forward(30) n.right(90) n.forward(1200) n.left(90) n.forward(30) n.left(90) n.forward(1200) n.right(90) def move_turtle(t, num1, num2): for y in range(0, 240): time.sleep(randint(num1, num2) * 0.02) t.forward(randint(1, 10)) return draw_background() ctrl = ThreadSerializer() colors = 'red', 'blue', 'green', 'orange', 'brown', 'black', 'pink', 'purple' threads = [] for i, color in enumerate(colors): t = turtle.Turtle() t.color(color) t.shape('turtle') t.penup() t.goto(-600, 270 - 30 * i) threads.append(TurtleThread(ctrl, t, target=move_turtle, args=[1, 10])) for thread in threads: thread.start() ctrl.run_forever() ,因为如果您不想更改它移动的距离,这是减慢乌龟速度的正确方法。

结果:

screenshot of turtle race taken seconds after start