如何在Python3.8.10中使用多处理而不使用time.sleep()时休眠进程
我使用大约1500 process multiprocessing.pool并行运行任务 在每个进程中,我需要每5分钟执行一次函数,即每5分钟我需要同时读取1500个文件。对于每个线程,我使用time.sleep(300-start_time)在函数执行结束时执行。然而,当尝试睡眠时,由于我的电脑中有16个内核,所以只执行16个进程,其余所有进程都不工作 代码如下:如何在Python3.8.10中使用多处理而不使用time.sleep()时休眠进程,python,multiprocessing,Python,Multiprocessing,我使用大约1500 process multiprocessing.pool并行运行任务 在每个进程中,我需要每5分钟执行一次函数,即每5分钟我需要同时读取1500个文件。对于每个线程,我使用time.sleep(300-start_time)在函数执行结束时执行。然而,当尝试睡眠时,由于我的电脑中有16个内核,所以只执行16个进程,其余所有进程都不工作 代码如下: import logging import os import pandas as pd import datetime as d
import logging
import os
import pandas as pd
import datetime as dt
os.chdir(os.path.dirname(os.path.abspath(__file__)))
from scipy.stats import linregress
from multiprocessing import Process, set_start_method, Pool, Value
import multiprocessing as mp
import traceback
import atr_bb as ab
import numpy as np
from operator import getitem
import datetime as dt
import time
import api as sa
import requests
def init(args):
''' store the counter for later use '''
global counter
counter = args
def train(string, dones, left_after):
global counter
count=0
t0 = dt.datetime.now()
time.sleep(300.0 - (t0.minute%5*60 + t0.second))
while(True):
count+=1
t0 = dt.datetime.now()
if(t0.hour>20):
return
print(string, " ", count)
func(string)# function to be performed
time.sleep(300.0 - (t0.minute%5*60 + t0.second) + 10)
except:
traceback.print_exc()
if __name__ == '__main__':
l = pd.read_csv('data.csv')['A']
counter = Value('i', 0)
mp.freeze_support()
mp_manager = mp.Manager()
data_dict = mp_manager.dict()
dones = mp_manager.list()
left = mp_manager.list()
args = []
for string in l:
args.append((str(string), dones, left))
p = Pool(initializer = init, initargs = (counter, ))
p.starmap(train, args)
p.close()
p.join()
现在,我怎样才能暂停一个进程一段时间,而CPU可以被其他进程利用呢?似乎是时间。sleep()仍在使用CPU,而其他字符串并没有被完全处理
根据BooBoo发布的答案2,我已经尝试了下面的代码,请您建议是否可以加快速度
import os
os.chdir(os.path.dirname(os.path.abspath(__file__)))
import logging
import pandas as pd
from scipy.stats import linregress
from multiprocessing import Process, set_start_method, Pool, Value
import multiprocessing as mp
import traceback
import atr_bb as ab
import numpy as np
from operator import getitem
import datetime as dt
import time
import stock_api as sa
import requests
import asyncio
import time
import signal
from multiprocessing import Manager
import sys
SLEEP_TIME = 5 * 60 # 5 minutes
async def train(x, lock):
loop = asyncio.get_running_loop()
"""
# I/O-bound portion:
import aiofiles
async with aiofiles.open(x, mode='r') as f:
data = await f.read()
# CPU-bound portion:
loop.run_in_executor(None, train_part2, data)
"""
# but no I/O-bound portion for this demo:
async with lock:
data = get_data(x)
loop.run_in_executor(None, train_part2, data, x)
def train_part2(data, x):
""" CPU-intensive portion """
print(x, " ", data.iloc[-1,-1]) # just print data
async def dispatcher(x, lock):
while(True):
t0 = dt.datetime.now()
if(t0.hour>=15):
return
t1 = time.time()
await train(x, lock)
t2 = time.time()
time_to_sleep = SLEEP_TIME - (t2 - t1)
if time_to_sleep > 0:
await asyncio.sleep(time_to_sleep)
async def main():
l = pd.read_csv('data.csv')['A']
lock = asyncio.Lock()
t0 = dt.datetime.now()
coroutines = ((dispatcher(x, lock)) for x in l)
await asyncio.gather(*coroutines)
t1 = dt.datetime.now()
print(t1-t0)
# Required for Windows:
if __name__ == "__main__":
with Manager() as manager:
asyncio.run(main())
我不认为池或你这样做的方式是最好的办法。如果您有一个池,它将有N个可以并行运行的工作线程。默认情况下,N是核心数。在你的情况下,工人做的第一件事就是睡觉。它阻止了池中的工人,但它什么也没做。您可以尝试增加池工作人员的数量,但如果您尝试启动1500名工作人员,则很可能会达到操作系统的限制 我的强烈建议是重新设计你的应用程序,这样你就可以在其他地方睡觉和等待,并且只在午睡时间结束后才将任务分派给泳池工作人员。不确定它是否适合您的情况,但您可以将线程和池结合起来。在线程中进行打盹,只有在有工作要做时才分派工作人员,并从池工作人员中移除所有睡眠 这只是一个虚拟片段来演示这个想法,但它可以运行
from multiprocessing import Pool
import threading
from time import sleep
def worker(x):
print(x)
def dispatcher(p, y):
p.apply(worker, args=(y,))
if __name__ == "__main__":
p = Pool()
for a in range(0,1500):
threading.Timer(5, dispatcher, [p,a]).start()
sleep(10)
p.close()
p.join()
在这个脚本中,worker()
是您的train()
。我的工人除了吐出序列号来证明它有效外,什么也不做。我添加了一个将在定时线程中运行的调度程序。这将完成等待,等待时间一结束,它就向池提交一个任务
如果您的train()
需要很长时间才能完成,则此操作仍会阻塞。你仍然只有有限数量的游泳池工人,如果他们被实际工作所阻碍,那么你就不走运了。您可以尝试将池大小增加一点,但不能增加到数千。这不会阻塞,因为您只需等待五分钟,就像线程等待您一样
如果您只想不断重复相同的任务,还可以使用dispatcher函数启动另一个计时器线程作为其最终任务。我知道您已经接受了答案。尽管如此,我还是建议使用
asyncio
corroutines的另一种方法,在创建如此大量(~15000)的并发任务时,这可能比线程更合适。此外,我想明确说明如何进行计时,以便重复操作(在您的情况下读取和处理文件,在我的示例中打印值)将在每5分钟执行一次的循环中完成
文件的实际读取是一个I/O绑定的“进程”,应该使用PyPI
存储库中的aiofiles
包来完成,正如我在评论中所指出的那样。然后,对已读取内容的CPU绑定处理应在进程池中完成,该功能由asyncio
提供:
导入异步IO
导入时间
输入信号
从多处理导入管理器
导入系统
睡眠时间=5*60#5分钟
异步def序列(x):
loop=asyncio.get\u running\u loop()
"""
#I/O绑定部分:
导入文件
将aiofiles.open(x,mode='r')作为f进行异步:
数据=等待f.读取()
#CPU绑定部分:
循环运行执行器(无,第2列,数据)
"""
#但此演示没有I/O绑定部分:
循环运行执行器(无,第2列,x部分)
def系列第2部分(数据):
“”“CPU密集型部分”“”
打印(数据)#只打印数据
异步def调度程序(x):
而不是终止_flag.value:
t1=时间。时间()
等待列车(x)
t2=时间。时间()
睡眠时间=睡眠时间-(t2-t1)
如果睡眠时间>0:
等待异步睡眠(时间到睡眠)
异步def main():
协同路由=(范围(15000)内x的调度程序(x))
等待asyncio.gather(*协同路由)
def句柄控制(信号、堆栈帧):
终止标志值=1
#Windows需要:
如果名称=“\uuuuu main\uuuuuuuu”:
使用Manager()作为管理器:
终止\u标志=manager.Value('i',0)
signal.signal(signal.SIGINT,handle_ctrl_c)#终止于ctrl-c
asyncio.run(main())
更新
下面是我如何将使用协同路由与访问Web服务器结合起来,并将抓取限制在每秒一定的速率:
导入异步IO
进口aiohttp
导入时间
输入信号
从多处理导入管理器
导入系统
#每秒10个请求(但对于15000个请求,这将需要25分钟)
每秒请求数=10
睡眠时间=5*60#5分钟
上一秒发出的请求=1
首次请求的时间=无
异步def序列(会话,x):
第一个请求的全局时间,最后一秒发出的请求
loop=asyncio.get\u running\u loop()
#确保每秒执行的请求不超过相应的请求数:
如果首次请求的时间为无:
首次请求的时间=time.time()
其他:
t=time.time()
如果t-首次请求的时间>=1:
#新的第二个间隔的开始
首次请求的时间=t
上一秒发出的请求=1
elif上一秒发出的请求<每秒请求数:
上一秒发出的请求数+=1
其他:
#必须等待新的秒数:
#这将阻止所有协同路由:
睡眠时间(首次请求的时间+1-t)
"""
#I/O绑定部分:
与se异步