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

2024-10-02 22:24:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我只是想知道,您如何创建一个循环,以便每次迭代都一个接一个地发生?我知道多线程是一种东西,我对此很熟悉。有一件事我搞不懂,那就是如何一个接一个地运行循环。在

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

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

def loop_b():
    while True:
        print("b")

如何使输出为ababababababababa,即使在第一个函数中有time.sleep(1)

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

有没有一种方法可以使用线程来实现这一点?在


Tags: 方法函数程序looptrue消息timedef
3条回答

您可以使用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)))

这是live example

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

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

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

#!/usr/bin/env python3
import time

from multiprocessing import Process, Event

并实现一个WorkerQueue类。这个类使工人保持正确的秩序,并负责开始和结束他们。工作人员之间的通信是使用事件实现的。每个worker都有其他的\u readyreadyEvent字段,它们相应地指示前一个worker和当前worker的完成状态。注意,如果队列中只有一个worker,那么它的其他准备就绪就绪是相同的。在

^{pr2}$

然后,我们通过继承Process类来实现工作进程本身。注意,也可以使用threading代替multiprocessing。在本例中,唯一更改的是Worker父类,Thread而不是{}。在

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)

在这里您可以看到,在开始执行命令之前,每个worker都会等待前一个工作线程就绪。默认情况下,other_ready已设置好,这样队列中只有一个工作线程时,我们不会遇到死锁。在

最后,我们实现了一个main函数,在这里我们定义了worker,将它们添加到worker队列中,并启动它们。在

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()的更全面的开发,使用了许多可用的实现策略之一:

^{pr2}$

此实现使用自旋锁并依赖线程安全共享变量lock来协调工作。旋转锁或旋转锁可能不适合您的应用。您可以将这些与一些阻塞机制结合使用,以减少处理过程中的一些延迟。在

关键是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

相关问题 更多 >