Python 如何阻止进程空闲或被终止?

Python 如何阻止进程空闲或被终止?,python,python-3.x,python-multiprocessing,python-multithreading,Python,Python 3.x,Python Multiprocessing,Python Multithreading,我需要处理数百万用户。我有数百万个用户ID,我从http请求中获取用户数据并写入文件 我使用多处理来执行这些任务的一批。然后,我在每个进程中使用多线程来成批执行任务。这大大提高了性能,使我能够以更快的速度处理更多的用户 问题: 我发现经过一段时间后,所有进程都变得不活动。我通过查看活动监视器了解这一点。一开始,我可以看到他们使用了大量的cpu和线程,过了一段时间,他们似乎空闲,我的程序挂起 导入操作系统 导入时间 导入日志记录 导入多处理 导入配置 导入json 从google.cloud导入存

我需要处理数百万用户。我有数百万个用户ID,我从http请求中获取用户数据并写入文件

我使用多处理来执行这些任务的一批。然后,我在每个进程中使用多线程来成批执行任务。这大大提高了性能,使我能够以更快的速度处理更多的用户

问题

我发现经过一段时间后,所有进程都变得不活动。我通过查看活动监视器了解这一点。一开始,我可以看到他们使用了大量的cpu和线程,过了一段时间,他们似乎空闲,我的程序挂起

导入操作系统
导入时间
导入日志记录
导入多处理
导入配置
导入json
从google.cloud导入存储
从pymongo导入MongoClient,UpdateOne
从队列导入队列
导入线程
来自多处理导入池的cpu\u计数
进程=多处理。cpu\u计数()-1
def get_tweet_对象(用户、计数器、锁、进程):
#删除(调用http请求并将json文件写入磁盘
lock.acquire()
尝试:
counter.value=counter.value+1
最后:
lock.release()
打印(“应用程序ID:{APP_ID},剩余:{APP_剩余},总用户:{TOTAL_USERS},用户:{USER_ID},TWEETS数量:{NO_TWEETS},所用时间:{TIME_taked}”
.format(app_id=app.app_id,app_剩余=0,total_users=counter.value,user_id=user[“user_id]”),no_tweets=len(total_tweets),time_take=round((end-start),2)),threading.current_thread().name,proc)
def添加任务(任务队列,任务):
对于任务中的任务:
任务队列.放置(任务)
返回任务队列
def进程任务(任务队列、计数器、锁):
logger=多处理。get_logger()
proc=os.getpid()
而不是任务队列。空()
尝试:
user=task\u queue.get()
多线程(用户、计数器、锁、进程)
例外情况除外,如e:
记录器错误(e)
info(f'Process{proc}已成功完成')
返回真值
def管理队列(任务队列、计数器、锁、过程):
尽管如此:
user=task\u queue.get()
获取_tweet_对象(用户、计数器、锁、进程)
任务队列。任务完成()
def do_多线程(批处理、计数器、锁、过程):
“”“启动多线程”“”
#设置线程数。
线程数=5
#初始化队列。
任务队列=队列()
#启动多线程
对于范围内的i(线程数):
t=threading.Thread(目标=管理队列,args=[
任务(队列、计数器、锁、进程])
t、 daemon=True
t、 开始()
对于分批处理:
任务队列.放置(批处理)
任务队列。加入()
def run():
mongodb=MongoClient(host=config.MONGO_URI)[“twitter”]
现有用户=mongodb[屏幕名称].find({}).limit(10000)
批次=创建批次(共100个)(现有用户)
空任务队列=多处理.Manager().queue()
完整任务队列=添加任务(空任务队列,批次)
进程=[]
计数器=多处理。值('i',0)
lock=multiprocessing.lock()
打印(f'Running with{PROCESSES}PROCESSES!')
开始=时间。时间()
对于范围内的w(工艺):
p=多处理。进程(
目标=进程任务,参数=(完整任务队列,计数器,锁))
进程。追加(p)
p、 开始()
对于流程中的p:
p、 加入
打印(f'Time take={Time.Time()-start:.10f}')
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
多处理.log_to_stderr(logging.ERROR)
运行()

因此,代码存在多个问题。首先,要不惜一切代价避免无限循环,比如在
manage\u queue
函数中。注意:我不是说“避免
,而为True:
”,因为这并不意味着它是一个无限循环(例如,你可以在它里面有
break

话虽如此,最大的问题(我们在聊天中的长时间讨论中发现)是
get\u tweet\u object()
函数有时会出现异常而失败,当出现异常时
task\u queue.task\u done()
永远不会被调用,因此
task\u queue.join()
永远不会退出

另一个问题是,将
而不是task\u queue.empty():
task\u queue.get()
混合是一种竞争条件。当两个并行线程运行且
task\u queue
正好有一个元素时会发生什么?其中一个元素将永远挂起。这应替换为
task\u queue.get(False)
使用适当的
队列。空的
捕获。它看起来像化妆品,但事实是竞争条件在
.get()
调用中处理。这样,您还需要在生成线程之前填充队列

总而言之,这里有一些变化:

from queue import Empty

def do_multithreading(batches, counter, lock, proc):
    """Starts the multithreading"""

    # Set the number of threads.
    number_of_threads = 5

    # Initializes the queue.
    for batch in batches:
        task_queue.put(batch)

    # Starts the multithreading
    for i in range(number_of_threads):
        t = threading.Thread(target=manage_queue, args=[
                             task_queue, counter, lock, proc])
        t.daemon = True
        t.start()
    task_queue.join()

def manage_queue(task_queue, counter, lock, proc):
    while True:
        try:
            user = task_queue.get(False)
        except Empty:
            break

        try:
            get_tweet_objects(user, counter, lock, proc)
        except Exception as exc:
            print(exc)
        finally:
            task_queue.task_done()

def process_tasks(task_queue, counter, lock):
    logger = multiprocessing.get_logger()
    proc = os.getpid()
    while True:
        try:
            user = task_queue.get(False)
        except Empty:
            break
        try:
            do_multithreading(user, counter, lock, proc)
        except Exception as e:
            logger.error(e)
        logger.info(f'Process {proc} completed successfully')
    return True

话虽如此,我还是强烈建议使用。

它们是空闲的,因为您有一个严重的漏洞:您的
manage\u队列
从不退出(即使队列是空的)您为每个用户生成了5个。如果您有10000个用户,那么很可能您的文件描述符已经用完了。如果您在每个用户中都接触http和文件,则可能会更快。但是您确实会记录错误,您的
处理任务
函数不会记录它们吗?@奇怪的是,我正在查找这些日志,它只是在get_tweet_objects functionOk,首先重构所有代码。使用而不是手动生成它们(你做错了)。然后永远不要允许像
manage_queue
这样的无限任务。对于执行者,您无论如何都会被迫这样做。我确信您的问题是描述符用完了,而日志记录无法工作,因为…描述符用完了。XD您可能会登录到文件,对吗?然后取决于底层日志记录实现在上,您可能看不到任何结果。如果没有文件描述符,您就是瞎子。谢谢,我可能一直在遵循一个旧的多处理指南。(edi)