我只是想知道,如何创建一个循环,使每次迭代都一次又一次地发生?我知道多线程是一回事,我对此很熟悉。我不知道的一件事是如何一个接一个地运行循环。
例如,假设我有2个功能:
def loop_a():
while True:
time.sleep(1)
print("a")
def loop_b():
while True:
print("b")
即使第一个功能中包含ababababababababa
,如何将输出设为time.sleep(1)
?
我正在使用 mpi4py ,并且想知道是否可以使用此库来执行此操作。 我的实际程序要求在函数之间发送消息。否则,使用任何其他python库(例如multiprocessing
都可以)。
是否可以使用线程来做到这一点?
答案 0 :(得分:0)
您可以使用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
唯一的想法是,除非您以某种方式同步它们,否则无法保证执行顺序。
答案 1 :(得分:0)
这是问题第一部分的解决方案-如何并行运行进程,以便每个进程等待上一个进程完成后才能开始处理任务。我在这里没有解决消息传递方面的问题,因为对我来说似乎有点含糊,可以根据问题说明以不同的方式实施。在此示例中,我们创建并运行三个工作程序,它们通过简单的时间延迟来模拟执行。代码段应保存在单个文件中,该文件可以从命令行运行。
我们首先导入所需的模块:
#!/usr/bin/env python3
import time
from multiprocessing import Process, Event
并实现WorkerQueue
类。此类使工人保持正确的秩序,并负责启动和终止他们。工人之间的交流是使用事件实现的。每个工作人员都有 other_ready 和 ready Event
字段,分别指示前一个工作人员和当前工作人员的完成状态。请注意,如果队列中只有一个工作线程,则其 other_ready 和 ready 相同。
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()
然后,我们通过继承Process
类来实现worker本身。请注意,也可以使用threading
代替multiprocessing
。在这种情况下,唯一改变的是Worker
父类Thread
而不是Process
。
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
这可能有点复杂,但这是我能想到的唯一解决方案。如果您知道更好的方法,我很乐意了解:)
答案 2 :(得分:0)
使用伪代码:
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
来协调工作。自旋锁可能适合或不适合您的应用。您可以将它们与某些阻止机制结合使用,以减少处理时间,但会导致处理延迟。
关键是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