gpt4 book ai didi

Python 3.8 shared_memory resource_tracker 在应用程序关闭时产生意外警告

转载 作者:行者123 更新时间:2023-12-04 11:11:37 52 4
gpt4 key购买 nike

  • 我正在使用 multiprocessing.Pool它在 1 个或多个子进程中调用一个函数来生成大量数据。
  • 工作进程创建一个 multiprocessing.shared_memory.SharedMemory对象并使用由 shared_memory 分配的默认名称.
  • worker 返回 SharedMemory 的字符串名称反对主进程。
  • 在主进程中SharedMemory对象被链接、消费,然后 取消链接和关闭 .

  • 在关闭时,我看到来自 resource_tracker 的警告:
    /usr/local/lib/python3.8/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: There appear to be 10 leaked shared_memory objects to clean up at shutdown
    warnings.warn('resource_tracker: There appear to be %d '
    /usr/local/lib/python3.8/multiprocessing/resource_tracker.py:229: UserWarning: resource_tracker: '/psm_e27e5f9e': [Errno 2] No such file or directory: '/psm_e27e5f9e'
    warnings.warn('resource_tracker: %r: %s' % (name, e))
    /usr/local/lib/python3.8/multiprocessing/resource_tracker.py:229: UserWarning: resource_tracker: '/psm_2cf099ac': [Errno 2] No such file or directory: '/psm_2cf099ac'
    <8 more similar messages omitted>
    由于我在主进程中取消了共享内存对象的链接,因此我对这里发生的事情感到困惑。我怀疑这些消息发生在子进程中(在本例中,我使用大小为 1 的进程池进行了测试)。
    这是一个最小的可重现示例:
    import multiprocessing
    import multiprocessing.shared_memory as shared_memory

    def create_shm():
    shm = shared_memory.SharedMemory(create=True, size=30000000)
    shm.close()
    return shm.name

    def main():
    pool = multiprocessing.Pool(processes=4)
    tasks = [pool.apply_async(create_shm) for _ in range(200)]

    for task in tasks:
    name = task.get()
    print('Getting {}'.format(name))
    shm = shared_memory.SharedMemory(name=name, create=False)
    shm.close()
    shm.unlink()

    pool.terminate()
    pool.join()

    if __name__ == '__main__':
    main()
    我发现在我自己的笔记本电脑(Linux Mint 19.3)上运行该示例运行良好,但是在两台不同的服务器机器(未知的操作系统配置,但两者不同)上运行它确实会出现问题。在所有情况下,我都从 docker 容器运行代码,因此 Python/软件配置是相同的,唯一的区别是 Linux 内核/主机操作系统。
    我注意到此文档可能相关: https://docs.python.org/3.8/library/multiprocessing.html#contexts-and-start-methods
    我还注意到“泄漏的共享内存对象”的数量因运行而异。因为我在主进程unlink,然后立即退出,也许这个 resource_tracker (我认为这是一个单独的进程)在主进程退出之前没有收到更新。我不明白 resource_tracker 的作用足以完全理解我刚刚提出的建议。
    相关话题:
  • https://bugs.python.org/issue39959
  • 最佳答案

    理论上和基于 SharedMemory 的当前实现,应该会出现警告。主要原因是您创建的每个共享内存对象都被跟踪两次:第一,当它由 Pool 中的一个进程生成时。目的;其次,当它被主进程消耗时。这主要是因为 SharedMemory 的构造函数的当前实现将 register共享内存对象不管是否create参数设置为 True或者它的值为 False .
    因此,当您拨打 shm.unlink() 时在主进程中,您正在做的是在其生产者( Pool 中的某个进程)开始清理它之前完全删除共享内存对象。结果,当池被销毁时,它的每个成员(如果他们有任务)都必须自行清理。第一个关于泄漏资源的警告可能是指Pool中进程实际创建的共享内存对象。从未得到过 unlinked 通过相同的过程 .而且,No such file or directory警告是由于主进程有 unlinked Pool 中的进程之前与共享内存对象关联的文件被摧毁。
    the linked bug report中提供的解决方案可能会阻止消费进程产生额外的资源跟踪器,但它并不能完全防止当消费进程决定删除它没有创建的共享内存对象时出现的问题。这是因为产生共享内存对象的进程仍然需要做一些清理,即一些 unlinking , 在它退出或被销毁之前。
    您没有看到这些警告这一事实令人费解。但这很可能与操作系统调度、子进程中未刷新的缓冲区以及创建进程池时使用的 start 方法的组合有关。
    为了比较,当我使用 fork作为我机器上的启动方法,我收到警告。否则,当 spawn 时我看不到警告和 forkserver被使用。我在您的代码中添加了参数解析,以便于测试不同的启动方法:

    #!/usr/bin/env python3
    # shm_test_script.py
    """
    Use --start_method or -s to pick a process start method when creating a process Pool.
    Use --tasks or -t to control how many shared memory objects should be created.
    Use --pool_size or -p to control the number of child processes in the create pool.
    """
    import argparse
    import multiprocessing
    import multiprocessing.shared_memory as shared_memory


    def create_shm():
    shm = shared_memory.SharedMemory(create=True, size=30000000)
    shm.close()
    return shm.name


    def main(tasks, start_method, pool_size):
    multiprocessing.set_start_method(start_method, force=True)
    pool = multiprocessing.Pool(processes=pool_size)
    tasks = [pool.apply_async(create_shm) for _ in range(tasks)]

    for task in tasks:
    name = task.get()
    print('Getting {}'.format(name))
    shm = shared_memory.SharedMemory(name=name, create=False)
    shm.close()
    shm.unlink()
    pool.terminate()
    pool.join()


    if __name__ == '__main__':
    parser = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter
    )
    parser.add_argument(
    '--start_method', '-s',
    help='The multiproccessing start method to use. Default: %(default)s',
    default=multiprocessing.get_start_method(),
    choices=multiprocessing.get_all_start_methods()
    )
    parser.add_argument(
    '--pool_size', '-p',
    help='The number of processes in the pool. Default: %(default)s',
    type=int,
    default=multiprocessing.cpu_count()
    )
    parser.add_argument(
    '--tasks', '-t',
    help='Number of shared memory objects to create. Default: %(default)s',
    default=200,
    type=int
    )
    args = parser.parse_args()
    main(args.tasks, args.start_method, args.pool_size)
    鉴于 fork是最终显示警告的唯一方法(至少对我而言),也许以下关于它的声明实际上有一些内容:

    The parent process uses os.fork() to fork the Python interpreter. Thechild process, when it begins, is effectively identical to the parentprocess. All resources of the parent are inherited by the childprocess. Note that safely forking a multithreaded process isproblematic.


    如果父进程的所有资源都由子进程继承,来自子进程的警告会持续/传播也就不足为奇了。
    如果您特别喜欢冒险,可以编辑 multiprocessing/resource_tracker.py并更新 warnings.warn行添加 os.getpid()到打印的字符串。例如,使用 "resource_tracker:" 更改任何警告至 "resource_tracker %d: " % (os.getpid())应该足够了。如果你这样做了,你会注意到警告来自各种进程,这些进程既不是子进程,也不是主进程本身。
    进行这些更改后,以下内容应该有助于仔细检查提示的资源跟踪器是否与您的 Pool 一样多。大小,并且它们的进程ID与主进程或子进程不同:
    chmod +x shm_test_script.py
    ./shm_test_script.py -p 10 -t 50 -s fork > log 2> err
    awk -F ':' 'length($4) > 1 { print $4 }' err | sort | uniq -c
    这应该显示十行,每行都预先加上来自相应资源跟踪器的投诉数量。每行还应该包含一个 PID,该 PID 应该不同于主进程和子进程。
    概括地说,如果每个子进程收到任何工作,它都应该有自己的资源跟踪器。由于您没有明确取消子进程中的共享内存对象的链接,因此当子进程被销毁时,资源可能会被清除。
    我希望这有助于回答您的一些问题,如果不是全部的话。

    关于Python 3.8 shared_memory resource_tracker 在应用程序关闭时产生意外警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62748654/

    52 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com