【问题标题】:Running interacting functions simultaneously in python在 python 中同时运行交互函数
【发布时间】:2018-04-17 03:18:03
【问题描述】:

所以我正在尝试构建一个可以自动驾驶的机器人。为此,我需要机器人向前行驶并同时检查距离。如果距离小于首选距离,则停止向前移动。到目前为止,我已经在下面编写了这段代码,但它似乎并没有同时运行,而且它们也没有交互。我怎样才能使这两个功能确实相互作用。如果需要更多信息,我很乐意为您提供。谢谢!

from multiprocessing import Process
from TestS import distance
import Robot
import time

constant1 = True
min_distance = 15

def forward():
    global constant1:
    robot.forward(150)                       #forward movement, speed 150
    time.sleep(2)

def distance_check():
    global constant1
    while constant1:
        distance()                           #checking distance
        dist = distance()
        return dist
        time.sleep(0.3)

        if dist < min_distance:
            constant1 = False
            print 'Something in the way!'
            break

def autonomy():                              #autonomous movement
    while True:
        p1 = Process(target=forward)         
        p2 = Process(target=distance_check)
        p1.start()                           #start up 2 processes
        p2.start()
        p2.join()                            #wait for p2 to finish

【问题讨论】:

  • 你能解释一下为什么他们不seem to run simultaniously或互动吗?你怎么知道的?

标签: python python-3.x python-multiprocessing python-multithreading


【解决方案1】:

所以,您发布的代码存在一些严重问题。首先,您不希望distance_check 进程完成,因为它正在运行一个while 循环。你不应该做p2.join(),也不应该在你的while循环中一直启动新进程。你在这里混合了太多的做事方式——两个孩子要么永远跑,要么他们每个跑一次,而不是混合。

然而,主要问题是原始进程无法与原始进程通信,即使通过global(除非您做更多工作)。线程更适合这个问题。

您的distance_check() 函数中还有一个return,因此该语句下面的代码不会被执行(包括sleepconstant1 的设置(应该真的有一个更好的名字)。

总之,我认为你想要这样的东西:

from threading import Thread
from TestS import distance
import Robot
import time

can_move_forward = True
min_distance = 15


def move_forward():
    global can_move_forward
    while can_move_forward:
        robot.forward(150)
        time.sleep(2)
        print('Moving forward for two seconds!')


def check_distance():
    global can_move_forward
    while True:
        if distance() < min_distance:
            can_move_forward = False
            print('Something in the way! Checking again in 0.3 seconds!')
        time.sleep(0.3)


def move_forward_and_check_distance():
    p1 = Thread(target = move_forward)
    p2 = Thread(target = check_distance)
    p1.start()
    p2.start()

由于您在标签中指定了 python-3.x,我还更正了您的 print

显然,我无法检查这是否可以按照您的意愿工作,因为我没有您的机器人,但我希望这至少有点帮助。

【讨论】:

  • 您可能希望使用queue 进行线程之间的通信。你知道线程不会同时运行吗?
  • @wwii 提问者似乎想使用全局变量。对于这么简单的事情,排队似乎有点过分了。我同意线程不会同时运行,但对于这种情况,它应该是同时运行的。
  • 感谢您的解决方案!我同意 constant1 应该有一个更好的名字。我正在尝试一些全局变量的东西,我认为它们适合这份工作。我也会试试你的代码!
  • 我真的很喜欢你的解决方案,因为它既好又简单。但它有一个缺陷。运行代码时,can_move_forward=False。之后它会短暂停止,然后再次向前移动很短的时间,然后最终停止。我想没有什么可做的,因为线程不会同时运行?
  • @NickHonings 我刚刚修复了check_distance 的错误(循环应该始终运行,而不仅仅是在can_move_forward 时运行)。我不知道这会如何导致问题,但也许可以尝试一下。此外,sleeps 可能过长 - 线程应该很快关闭,因此代码中可能存在任何延迟。
【解决方案2】:

您的多处理解决方案的一个问题是distance_check 返回并停止

    dist = distance()
    return dist        # <------ 
    time.sleep(0.3)

    if dist < min_distance:
        ....

您似乎正在尝试在进程之间交换信息:这通常使用Queues or Pipes 完成。

阅读了您问题的字里行间,并提出了以下规范:

  • 如果机器人的速度大于零,机器人就会移动
  • 不断检查机器人前方的障碍物
  • 如果机器人接近某物,请停止它。

我认为您可以在不使用多处理的情况下实现您的目标。这是一个使用生成器/协程的解决方案。

出于测试目的,我编写了自己的机器人版本和障碍物传感器 - 试图模仿我在您的代码中看到的内容

class Robot:
    def __init__(self, name):
        self.name = name
    def forward(self, speed):
        print('\tRobot {} forward speed is {}'.format(self.name, speed))
        if speed == 0:
            print('\tRobot {} stopped'.format(speed))

def distance():
    '''User input to simulate obstacle sensor.'''
    d = int(input('distance? '))
    return d

Decorator to start a coroutine/generator:

def consumer(func):
    def wrapper(*args,**kw):
        gen = func(*args, **kw)
        next(gen)
        return gen
    wrapper.__name__ = func.__name__
    wrapper.__dict__ = func.__dict__
    wrapper.__doc__  = func.__doc__
    return wrapper

生产者不断检查是否可以安全移动

def can_move(target, min_distance = 15):
    '''Continually check for obstacles'''
    while distance() > min_distance:
        target.send(True)
        print('check distance')
    target.close()

一个生成器/协程,消耗安全移动信号并根据需要改变机器人的速度。

@consumer
def forward():
    try:
        while True:
            if (yield):
                robot.forward(150)
    except GeneratorExit as e:
        # stop the robot
        robot.forward(0)

机器人的速度变化应与障碍物传感器产生距离的速度一样快。机器人将向前移动,直到它接近某物并停止,然后它全部关闭。通过稍微调整forwardcan_move 中的逻辑,您可以更改行为,以便生成器/协程继续运行,但只要有东西在它前面,然后当它离开时发送零速命令方式(或机器人转动)它将再次开始移动。

用法:

>>> 
>>> robot = Robot('Foo')
>>> can_move(forward())
distance? 100
    Foo forward speed is 150
check distance
distance? 50
    Foo forward speed is 150
check distance
distance? 30
    Foo forward speed is 150
check distance
distance? 15
    Foo forward speed is 0
    Robot 0 stopped
>>>

虽然这在 Python 3.6 中有效,但它基于对生成器和协程的可能过时的概念/理解。使用 Python 3+ 中的一些 async 添加可能有不同的方法。

【讨论】:

  • 首先非常感谢您的回复!我试图了解您的代码,因为我只是一个初学者。但我开始理解你的方法,我一定会尝试的!
猜你喜欢
  • 2010-12-19
  • 2012-05-20
  • 2020-08-08
  • 1970-01-01
  • 2017-02-07
  • 2012-07-12
  • 1970-01-01
  • 1970-01-01
  • 2022-08-22
相关资源
最近更新 更多