跳转到主要内容

更简单的Python多进程编码。持久化工作者,内存映射以最小化开销。

项目描述

Python 多核

一个使Python代码并行化变得简单的模块。

Travis

安装

  1. multicore安装或添加到Python路径中。

概述

Python支持多线程,但全局解释器锁(GIL)阻止了我们充分利用所有CPU核心进行CPU密集型任务。建议的方法是使用Python的multiprocessing库来绕过GIL,但这也有其自身的挑战,尤其是子进程间共享数据的能力有限。

多核库的目的是在尽可能少的开销下简化代码的并行化。

功能

  1. 持久的工人类别,支持持久的数据库连接。

  2. 使用内存映射进行进程间通信,比多进程的IPC或管道快得多。

  3. 会考虑系统负载平均值来决定在任何给定时间并行化是否值得。

架构

Python多核实际上是一个内存队列,由一组固定的工人处理。它使用内存映射来避免使用celery等队列系统带来的延迟。

用法

让我们渲染100个用户。始终将大任务分解成小任务,但不要过于细分!如果范围太小,那么任务不值得努力,因为开销太大。

import time

from multicore import initialize, shutdown, Task
from multicore.utils import ranges


# Note the scoping of the "items" variable and the functions
items = range(100)


def as_string(item):
    return str(item)


def expensive_as_string(item):
    time.sleep(0.01)
    return str(item)


def multi_expensive_as_string(start, end):
    return ",".join([expensive_as_string(item) for item in items[start:end]])


if __name__ == "__main__":

    # Needs to be called only once for lifetime of process
    initialize()

    # Example 1: trivial (and slightly pointless) usage
    task = Task()
    for i in range(20):
        task.run(as_string, i)
    print(", ".join(task.get()))

    # Example 2: divide job optimally using ranges function
    task = Task()
    for start, end in ranges(items):
        # Note we don't pass items because pickling is expensive and defeats
        # the purpose of the exercize.
        task.run(multi_expensive_as_string, start, end)
    print(", ".join(task.get()))

    # Stop the multicore workers
    shutdown()

Task构造函数接受一个可选的参数max_load_average。如果过去一分钟的负载平均值大于定义的阈值,则返回None,并且你的代码必须处理顺序代码路径。注意,阈值是针对单核机器指定的,所以通常小于1。

run方法接受一个可选的参数serialization_format,其值为pickle(默认),jsonstring。Pickle速度慢但安全。如果你知道你有什么类型的数据(你应该知道!)则设置适当。

run方法还接受一个可选的参数use_dill,默认值为False。Dill是一个库,它可以通常序列化那些不能由标准序列化器序列化的内容,但它稍微慢一些。

常见问题解答

它是否会尝试并行执行数百条代码?

不。工作池的大小是固定的,只能并行执行与核心数相同数量的任务。你也可以设置max_load_average作为额外的保护措施。

为什么没有使用multiprocessing.Pool?

它在与Django等工具的范围内存在太多问题。甚至管道和套接字也会引入太多的开销,因此使用内存映射。

您有任何基准测试吗?

不,因为这个只是一个接口,不是一个并行代码集合。

一般来说,如果你不访问数据库,代码的扩展几乎是线性的。在我的机器上,多核本身增加了大约5毫秒的开销。

内存映射对于我的数据结构来说太小了

未来的版本将通过动态内存映射扩展来解决此问题。

作者

Praekelt Consulting

  • Hedley Roos

变更日志

0.1.1

  1. 更新readme以包含一个工作示例。

  2. 防止尝试重新使用已完成的任务。

0.1

  1. 初始发布。

项目详情


下载文件

下载适合您的平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源分发

multicore-0.1.1.tar.gz (23.1 kB 查看哈希值)

上传时间

构建分发

multicore-0.1.1-py2.7.egg (15.7 kB 查看散列值)

上传时间

由以下支持