Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 2个for循环能否同时运行,一个接一个地循环?_Python_Multithreading_Loops_Mpi_Theory - Fatal编程技术网

Python 2个for循环能否同时运行,一个接一个地循环?

Python 2个for循环能否同时运行,一个接一个地循环?,python,multithreading,loops,mpi,theory,Python,Multithreading,Loops,Mpi,Theory,我只是想知道,如何创建一个循环,使每个迭代一个接一个地发生?我知道多线程是一件事,我对它很熟悉。有一件事我搞不懂,那就是如何一个接一个地运行循环 例如,假设我有两个函数: def loop_a(): while True: time.sleep(1) print("a") def loop_b(): while True: print("b") 如何使输出成为abababababababa,即使时间。sleep(1)出现在第一个

我只是想知道,如何创建一个循环,使每个迭代一个接一个地发生?我知道多线程是一件事,我对它很熟悉。有一件事我搞不懂,那就是如何一个接一个地运行循环

例如,假设我有两个函数:

def loop_a():
    while True:
        time.sleep(1)
        print("a")

def loop_b():
    while True:
        print("b")
如何使输出成为
abababababababa
,即使
时间。sleep(1)
出现在第一个函数中?

我正在使用mpi4py,不知道是否有任何方法可以使用这个库来实现这一点我的实际程序需要在函数之间发送消息。否则,使用任何其他python库,如
多处理
都可以

有没有一种方法可以使用线程处理

您可以使用corutines:

import asyncio

q = asyncio.Queue()

async def loop_a(q):
  for i in range(10):
    value = await q.get()
    print(value)

async def loop_b(q):
  for i in range(10):
    await q.put("a")
    print("b")


loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(loop_a(q), loop_b(q)))
给你钱


唯一的想法是,除非您以某种方式同步它们,否则无法保证执行顺序。

以下是问题第一部分的解决方案-如何并行运行进程,以便每个进程都等待前一个进程完成后开始处理任务。我在这里没有提到消息传递方面,因为它对我来说有点模糊,并且可以根据问题陈述以不同的方式实现。在本例中,我们创建并运行了三个worker,它们通过简单的时间延迟来模拟执行。代码段应保存到单个文件中,该文件可以从命令行运行

我们首先导入所需的模块:

#!/usr/bin/env python3
import time

from multiprocessing import Process, Event
实现一个
WorkerQueue
类。该类使工人保持正确的顺序,并负责启动和终止工人。工作人员之间的通信是使用事件实现的。每个工人都有其他准备就绪准备就绪
事件
字段,相应地指示前一个工人和当前工人的完成状态。注意,如果队列中只有一个worker,则其其他准备就绪准备就绪是相同的

class WorkerQueue(object):

    def __init__(self):
        self._workers = []

    def add_worker(self, worker):

        if self._workers:
            worker.other_ready = self._workers[-1].ready
            self._workers[0].other_ready = worker.ready
        else:
            worker.other_ready = worker.ready

        self._workers.append(worker)

    def start_workers(self):

        if not self._workers:
            return

        self._workers[0].other_ready.set()

        for w in self._workers:
            w.start()

    def stop_workers(self):

        for w in self._workers:
            w.join()
然后,我们通过继承
进程
类来实现worker本身。注意,也可以使用
线程
而不是
多处理
。在这种情况下,唯一更改的是
工作者
父类,
线程
,而不是
进程

class Worker(Process):

    def __init__(self, delay, name=None):
        super().__init__(name=name)
        self.delay = delay
        self.other_ready = Event()
        self.other_ready.set()
        self.ready = Event()
        self.stop = Event()

    def run(self):

        while not self.stop.is_set():

            try:
                self.other_ready.wait()

                t = time.strftime('%H:%M:%S')
                print('Started:', self.name, t, flush=True)

                time.sleep(self.delay)

                t = time.strftime('%H:%M:%S')
                print('Finished:', self.name, t, flush=True)
            except:
                break

            self.other_ready.clear()
            self.ready.set()

    def join(self, timeout=None):
        self.stop.set()
        super().join(timeout)
在这里,您可以看到,每个工作进程在开始执行命令之前都会等待前一个工作进程准备就绪。默认情况下,other_ready被设置为在队列中只有一个工作进程的情况下不会发生死锁

最后,我们实现了一个
main
函数,在该函数中定义工人,将他们添加到工人队列,然后启动他们

def main():
    first = Worker(delay=1, name='first')
    second = Worker(delay=3, name='second')
    third = Worker(delay=2, name='third')

    queue = WorkerQueue()

    for w in (first, second, third):
        queue.add_worker(w)

    queue.start_workers()

    try:

        # The main infinite loop, do something useful:
        while True:
            time.sleep(1)

    except KeyboardInterrupt:
        pass
    finally:
        queue.stop_workers()
不要忘记在文件末尾添加以下行:

if __name__ == '__main__':
    main()
现在,可以将其保存到一个文件中,例如
proc_queue.py
,您可以从命令行运行该文件以查看结果:

$ python3 proc_queue.py 
Started: first 16:04:09
Finished: first 16:04:10
Started: second 16:04:10
Finished: second 16:04:13
Started: third 16:04:13
Finished: third 16:04:15
Started: first 16:04:15
Finished: first 16:04:16
Started: second 16:04:16
Finished: second 16:04:19
Started: third 16:04:19
Finished: third 16:04:21
^C
这可能有点过于复杂,但这是我能想到的唯一解决方案。如果您知道更好的方法,我很乐意学习:)

伪代码:

main()
1. set lock for loop1
2. start loop1 on background thread
3. start loop2 on background thread
4. wait

loop1()
1. do the following forever:
2.    acquire lock for loop1
3.    print 'a'
4.    release lock for loop2

loop2()
1. do the following forever:
2.    acquire lock for loop2
3.    print 'b'
4.    release lock for loop1
您可以将锁实现为一个共享内存变量,或者作为一个等待从对等方获取消息的循环,或者其他任何形式。获取锁意味着阻塞或旋转锁定(轮询),直到锁准备就绪;释放锁将适当地设置共享变量或向正确的对等方发送正确的消息

编辑:根据一条评论,下面是对loop1()和loop2()的更全面的开发,使用了许多可用的实现策略之一:

(shared lock in global scope)

main()
1. lock = 1
2. start loop1 on background thread
3. start loop2 on background thread
4. wait

loop1()
1. do the following forever
2.    loop until lock = 1
3.    print 'a'
4.    lock = 2

loop2()
1. do the following forever
2.    loop until lock = 2
3.    print 'b'
4.    lock = 1
此实现使用旋转锁,并依赖线程安全的共享变量
lock
来协调工作。旋转锁可能适合也可能不适合您的应用程序。您可以将它们与一些阻塞机制结合使用,以减少处理时间,但代价是处理过程中的一些延迟

关键是
锁是有状态的,并且(应该)只能由正确的线程获取。如果每个线程都“意识到”了“下一个”线程,并在完成时发送消息,则可以对消息传递执行相同的操作。。。然后所有线程都会等待收到消息

main()
1. start loop1 on background thread
2. start loop2 on background thread
3. message loop1
4. wait

loop1()
1. do the following forever
2.    loop until message received
3.    print 'a'
4.    message loop2

loop2()
1. do the following forever
2.    loop until message received
3.    print 'b'
4.    message loop1

不过,这只是一个例子。为了解释,函数可能具有
while
循环,而不是
for
循环。还有更复杂的事情(比如在每个函数之间传递消息)。我不认为这个解决方案适合我的需要,所以让我改变这个问题,我应该怎样做(包括循环)我更新了它。我会用考鲁廷来做。我没有检查问题中的通信内容。运行此代码将打印
aaaaaabbbbb
bbbbbbaaaaaa
。它不起作用这听起来像个XY问题。你为什么想要这个输出?你需要达到的实际行为是什么?请在你的问题中包含更多关于循环中完成的工作之间依赖关系的细节。尽管看起来很简单,但它不起作用。这是我想到的第一个想法,所以我先测试了一下。问题是一个线程可以在第二个线程之前多次获得锁。此外,您不能保证线程执行的顺序。@const否,如果您正确地实现它,它确实可以工作。您缺少“for loop1”和“for loop2”部分。仅当锁处于正确状态时,“获取”方法才应获取锁。锁可以是“可用于loop1”和“可用于loop2”,并且在这些情况下只能由相应的循环获取。这修复了“多次采集”问题并保证了确定性排序(注意Main()程序如何将锁的状态设置为“可用于loop1”)。这是关键。不要只拥有0/1共享计数器或“可用”广播;使其有状态。(如果您不想让循环相互了解,那么很好;实现loc