使用 cProfile 对其他完美工作的多处理 python 脚本进行分析时出错 [重复]

2023-12-23

我写了一个小的 python 脚本,使用multiprocessing (See https://stackoverflow.com/a/41875711/1878788 https://stackoverflow.com/a/41875711/1878788)。当我测试它时它有效:

$ ./forkiter.py
0
1
2
3
4
sum of x+1: 15
sum of 2*x: 20
sum of x*x: 30

但是当我尝试用它来分析它时cProfile,我得到以下信息:

$ python3.6 -m cProfile -o forkiter.prof ./forkiter.py
0
1
2
3
4
Traceback (most recent call last):
  File "/home/bli/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/bli/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/bli/lib/python3.6/cProfile.py", line 160, in <module>
    main()
  File "/home/bli/lib/python3.6/cProfile.py", line 153, in main
    runctx(code, globs, None, options.outfile, options.sort)
  File "/home/bli/lib/python3.6/cProfile.py", line 20, in runctx
    filename, sort)
  File "/home/bli/lib/python3.6/profile.py", line 64, in runctx
    prof.runctx(statement, globals, locals)
  File "/home/bli/lib/python3.6/cProfile.py", line 100, in runctx
    exec(cmd, globals, locals)
  File "./forkiter.py", line 71, in <module>
    exit(main())
  File "./forkiter.py", line 67, in main
    sum_tuples, results_generator))
  File "/home/bli/lib/python3.6/multiprocessing/pool.py", line 699, in next
    raise value
  File "/home/bli/lib/python3.6/multiprocessing/pool.py", line 385, in _handle_tasks
    put(task)
  File "/home/bli/lib/python3.6/multiprocessing/connection.py", line 206, in send
    self._send_bytes(_ForkingPickler.dumps(obj))
  File "/home/bli/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <class '__main__.FuncApplier'>: attribute lookup FuncApplier on __main__ failed

会发生什么?

这是脚本:

#!/usr/bin/env python3
"""This script tries to work around some limitations of multiprocessing."""

from itertools import repeat, starmap
from multiprocessing import Pool
from functools import reduce
from operator import add
from time import sleep

# Doesn't work because local functions can't be pickled:
# def make_tuple_func(funcs):
#     def tuple_func(args_list):
#         return tuple(func(args) for func, args in zip(funcs, args_list))
#     return tuple_func
#
# test_tuple_func = make_tuple_func((plus_one, double, square))

class FuncApplier(object):
    """This kind of object can be used to group functions and call them on a
    tuple of arguments."""
    __slots__ = ("funcs", )

    def __init__(self, funcs):
        self.funcs = funcs

    def __len__(self):
        return len(self.funcs)

    def __call__(self, args_list):
        return tuple(func(args) for func, args in zip(self.funcs, args_list))

    def fork_args(self, args_list):
        """Takes an arguments list and repeat them in a n-tuple."""
        return tuple(repeat(args_list, len(self)))


def sum_tuples(*tuples):
    """Element-wise sum of tuple items."""
    return tuple(starmap(add, zip(*tuples)))


# Can't define these functions in main:
# They wouldn't be pickleable.
def plus_one(x):
    return x + 1

def double(x):
    return 2 * x

def square(x):
    return x * x

def main():
    def my_generator():
        for i in range(5):
            print(i)
            yield i


    test_tuple_func = FuncApplier((plus_one, double, square))

    with Pool(processes=5) as pool:
        results_generator = pool.imap_unordered(
            test_tuple_func,
            (test_tuple_func.fork_args(args_list) for args_list in my_generator()))
        print("sum of x+1:\t%s\nsum of 2*x:\t%s\nsum of x*x:\t%s" % reduce(
            sum_tuples, results_generator))
    exit(0)

if __name__ == "__main__":
    exit(main())

一些酸洗测试

一些研究表明,有时物体需要一个__setstate__ and __getstate__可腌制的方法。这对某些酸洗协议有帮助,但这似乎并不能解决问题cProfile案件。 请参阅下面的测试。

更新后的脚本:

#!/usr/bin/env python3
"""This script tries to work around some limitations of multiprocessing."""

from itertools import repeat, starmap
from multiprocessing import Pool
from functools import reduce
from operator import add
from time import sleep
import pickle

# Doesn't work because local functions can't be pickled:
# def make_tuple_func(funcs):
#     def tuple_func(args_list):
#         return tuple(func(args) for func, args in zip(funcs, args_list))
#     return tuple_func
#
# test_tuple_func = make_tuple_func((plus_one, double, square))

class FuncApplier(object):
    """This kind of object can be used to group functions and call them on a
    tuple of arguments."""
    __slots__ = ("funcs", )

    def __init__(self, funcs):
        self.funcs = funcs

    def __len__(self):
        return len(self.funcs)

    def __call__(self, args_list):
        return tuple(func(args) for func, args in zip(self.funcs, args_list))

    # Attempt to make it pickleable when under cProfile (doesn't help)
    def __getstate__(self):
        return self.funcs

    def __setstate__(self, state):
        self.funcs = state

    def fork_args(self, args_list):
        """Takes an arguments list and repeat them in a n-tuple."""
        return tuple(repeat(args_list, len(self)))


def sum_tuples(*tuples):
    """Element-wise sum of tuple items."""
    return tuple(starmap(add, zip(*tuples)))


# Can't define these functions in main:
# They wouldn't be pickleable.
def plus_one(x):
    return x + 1

def double(x):
    return 2 * x

def square(x):
    return x * x

def main():
    def my_generator():
        for i in range(5):
            print(i)
            yield i


    test_tuple_func = FuncApplier((plus_one, double, square))

    print("protocol 0")
    try:
        print(pickle.dumps(test_tuple_func, 0))
    except pickle.PicklingError as err:
        print("failed with the following error:\n%s" % err)
    print("protocol 1")
    try:
        print(pickle.dumps(test_tuple_func, 0))
    except pickle.PicklingError as err:
        print("failed with the following error:\n%s" % err)
    print("protocol 2")
    try:
        print(pickle.dumps(test_tuple_func, 0))
    except pickle.PicklingError as err:
        print("failed with the following error:\n%s" % err)
    print("protocol 3")
    try:
        print(pickle.dumps(test_tuple_func, 0))
    except pickle.PicklingError as err:
        print("failed with the following error:\n%s" % err)
    print("protocol 4")
    try:
        print(pickle.dumps(test_tuple_func, 0))
    except pickle.PicklingError as err:
        print("failed with the following error:\n%s" % err)

    with Pool(processes=5) as pool:
        results_generator = pool.imap_unordered(
            test_tuple_func,
            (test_tuple_func.fork_args(args_list) for args_list in my_generator()))
        print("sum of x+1:\t%s\nsum of 2*x:\t%s\nsum of x*x:\t%s" % reduce(
            sum_tuples, results_generator))
    exit(0)

if __name__ == "__main__":
    exit(main())

测试无cProfile看起来不错:

$ ./forkiter.py
protocol 0
b'ccopy_reg\n_reconstructor\np0\n(c__main__\nFuncApplier\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(c__main__\nplus_one\np5\nc__main__\ndouble\np6\nc__main__\nsquare\np7\ntp8\nb.'
protocol 1
b'ccopy_reg\n_reconstructor\np0\n(c__main__\nFuncApplier\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(c__main__\nplus_one\np5\nc__main__\ndouble\np6\nc__main__\nsquare\np7\ntp8\nb.'
protocol 2
b'ccopy_reg\n_reconstructor\np0\n(c__main__\nFuncApplier\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(c__main__\nplus_one\np5\nc__main__\ndouble\np6\nc__main__\nsquare\np7\ntp8\nb.'
protocol 3
b'ccopy_reg\n_reconstructor\np0\n(c__main__\nFuncApplier\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(c__main__\nplus_one\np5\nc__main__\ndouble\np6\nc__main__\nsquare\np7\ntp8\nb.'
protocol 4
b'ccopy_reg\n_reconstructor\np0\n(c__main__\nFuncApplier\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(c__main__\nplus_one\np5\nc__main__\ndouble\np6\nc__main__\nsquare\np7\ntp8\nb.'
0
1
2
3
4
sum of x+1: 15
sum of 2*x: 20
sum of x*x: 30

cProfile 下的测试在每个酸洗协议中都失败(因此在多处理中也是如此):

$ python3.6 -m cProfile -o forkiter.prof ./forkiter.py
protocol 0
failed with the following error:
Can't pickle <class '__main__.FuncApplier'>: attribute lookup FuncApplier on __main__ failed
protocol 1
failed with the following error:
Can't pickle <class '__main__.FuncApplier'>: attribute lookup FuncApplier on __main__ failed
protocol 2
failed with the following error:
Can't pickle <class '__main__.FuncApplier'>: attribute lookup FuncApplier on __main__ failed
protocol 3
failed with the following error:
Can't pickle <class '__main__.FuncApplier'>: attribute lookup FuncApplier on __main__ failed
protocol 4
failed with the following error:
Can't pickle <class '__main__.FuncApplier'>: attribute lookup FuncApplier on __main__ failed
0
1
2
3
4
Traceback (most recent call last):
  File "/home/bli/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/bli/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/bli/lib/python3.6/cProfile.py", line 160, in <module>
    main()
  File "/home/bli/lib/python3.6/cProfile.py", line 153, in main
    runctx(code, globs, None, options.outfile, options.sort)
  File "/home/bli/lib/python3.6/cProfile.py", line 20, in runctx
    filename, sort)
  File "/home/bli/lib/python3.6/profile.py", line 64, in runctx
    prof.runctx(statement, globals, locals)
  File "/home/bli/lib/python3.6/cProfile.py", line 100, in runctx
    exec(cmd, globals, locals)
  File "./forkiter.py", line 105, in <module>
    exit(main())
  File "./forkiter.py", line 101, in main
    sum_tuples, results_generator))
  File "/home/bli/lib/python3.6/multiprocessing/pool.py", line 699, in next
    raise value
  File "/home/bli/lib/python3.6/multiprocessing/pool.py", line 385, in _handle_tasks
    put(task)
  File "/home/bli/lib/python3.6/multiprocessing/connection.py", line 206, in send
    self._send_bytes(_ForkingPickler.dumps(obj))
  File "/home/bli/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <class '__main__.FuncApplier'>: attribute lookup FuncApplier on __main__ failed

它似乎cProfile根本不适用于多处理。

如果您愿意修改代码,仅分析主流程(或为子流程添加特定分析),cProfile.run()似乎在一定程度上起作用。

在您的示例中,替换

exit(main())

with

exit(cProfile.run('main()')

如果并行函数是全局作用域函数,那么这至少有效,但不确定对于像您这样的类来说也是如此。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 cProfile 对其他完美工作的多处理 python 脚本进行分析时出错 [重复] 的相关文章

随机推荐

  • Java 命令在 NLTK 斯坦福 POS Tagger 中失败

    我请求您帮助解决 Java 命令失败 错误 每当我尝试标记大小为 2 MB 的阿拉伯语语料库时 该错误就会不断抛出 我搜索了网络和 stanford POS tagger 邮件列表 但是 我没有找到解决方案 我读了一些关于类似问题的帖子 有
  • 等待多个异步下载任务

    我想同时下载一些文件 例如 100 个文件 所以我决定将我的下载线程添加到调度队列中 GCD 将调整同时运行的线程数量 这里的问题是 dispatch async将立即完成 因为task将在另一个线程上运行 因此 如果urls的长度是100
  • Flex 自定义组件不接受脚本:“String”类型的默认属性“text”的多个初始值设定项值

    我正在使用 Flex 4 和 Flash Builder 4 我只是想学习创建组件 我创建了一个 mxml 组件 如下所示并将其包含在我的应用程序中
  • 如何在 VB.NET 中引发事件之前检查订阅者

    在 C 中 您可以执行以下操作 if Changed null Changed this EventArgs Empty 但是您在 VB NET 中做什么呢 有RaiseEvent but is RaiseEvent Changed Me
  • 更改按钮文本和操作 - Android 开发

    我无法弄清楚如何更改按钮的文本和操作 我想要做的是有一个带有文本 播放 的按钮 单击它会播放一首歌曲并将文本更改为 暂停 然后 当您再次单击它时 它将暂停歌曲并将文本更改为 播放 我知道如何使用媒体播放器 编码 只是不知道如何以这种方式编码
  • 线程完成工作后如何返回值?

    假设我们有一个简单的例子 public Example extends Thread String temp public Example Override public void run temp a value public stati
  • 鞍点的位置

    我有以下问题 假设我们有一个9 8的矩阵 如果矩阵位于某个位置 则称其具有 鞍点 是其行中的最小值和其列中的最大值 在符号 中 a i j 是鞍点 如果 a i j min a i k max a k k 1 lt k lt 8 1 lt
  • 使用Python的正则表达式将浮点数替换为“dot”

    我想替换 出现在我的字符串中带有 点 的浮点数中 反之亦然 Example t I am coder I work in Google I earn 98748 85 Expected output I am coder I work in
  • R 中的字符编码

    我正在尝试阅读csv由 Sql Server Management Studio 生成并编码为的文件UTF 8 我保存时选择了该选项 到R版本 3 0 1 x64 至read csv2 我无法让 R 正确显示特殊字符 如果我设置fileEn
  • 从字符串中获取整数月份值

    我正在解析来自 AWS 的 cron 字符串 如下所示cron 0 7 13 November 2019 有没有一种干净的方式可以从November回到11使用 Go 的内置类型 这time Month类型允许映射int to string
  • 从亚马逊 s3 存储桶子文件夹获取文件

    我正在尝试从亚马逊 S3 存储桶子文件夹中获取所有文件 并使它们可以在网页中下载 我有一个名为图像的桶 在那个桶里我还有一些其他文件夹 现在我试图获取该子文件夹内的所有文件并将其显示在页面中 S3 桶 图片 图像 测试1 图像 测试2 图像
  • SQL 声明变量

    谁能看一下我的发言 DECLARE tblName varchar MAX strSQL varchar MAX SET tblName SELECT DISTINCT o name as TableName FROM sysobjects
  • 如何将 SQL Server 2005 数据传输或导出到 Excel

    我有一个简单的 SQL 选择 查询 我想将结果转储到 Excel 文件中 我只能另存为 csv 并转换为 xls 会产生一些超级丑陋的输出 无论如何 据我所知 使用谷歌 这似乎并不那么简单 任何帮助将不胜感激 SSIS 做这样的事情是轻而易
  • 如何更改 NsdManager 使用的 Android 设备名称?

    我正在使用 NsdManager 在本地网络上注册 Web 服务 我的问题是设备名称称为 android 因此我可以从笔记本电脑上以 android local 身份访问手机 我怎样才能改变这个名字 我想要一些更独特的东西 您无法更改此设置
  • 使用 www::mechanize 时的 Iconv::IllegalSequence

    我正在尝试做一些网络抓取 但 WWW Mechanize gem 似乎不喜欢编码并且崩溃 post 请求导致 302 重定向 机械化遵循 到目前为止一切顺利 并且生成的页面似乎使其崩溃 我用谷歌搜索了很多 但到目前为止还没有找到如何解决这个
  • 如何更改 QPlainTextEdit 中选项卡的宽度

    When using the QPlaintextEdit in PyQt5 if I press the Tab button on my keyboard I get a tab space which is equal to size
  • Django 管理员未对用户密码进行哈希处理

    我在用AbstractBaseUser and UserCreationForm与我的 Django 应用程序 通过我的应用程序注册用户时 密码以哈希格式保存并保存在数据库中 但是当我尝试使用 Django 管理站点执行相同的操作时 密码会
  • 使用多个 Docker 容器 VS 标准 Node 集群时的性能和可靠性

    使用多个 Docker 容器 VS 标准 Node 集群时的性能和可靠性 您好 我有一个关于我遇到的两种设置的性能 可靠性和增长潜力的问题 我距离 Docker 或集群专家还很远 所以任何建议或提示将不胜感激 The app Typical
  • PhoneGap Build 中 Android 的横向启动屏幕

    我应该输入什么config xml或者我一般应该做什么 才能让 PhoneGap Build 应用程序的启动屏幕在横向模式下在 Android 设备上正确显示 PhoneGap Build 用于编译 docs https build pho
  • 使用 cProfile 对其他完美工作的多处理 python 脚本进行分析时出错 [重复]

    这个问题在这里已经有答案了 我写了一个小的 python 脚本 使用multiprocessing See https stackoverflow com a 41875711 1878788 https stackoverflow com