如何在python中并行化一个函数

时间:2017-03-21 23:29:13

标签: python multiprocessing

我有一个令人尴尬的并行问题,但一直想知道如何“设计”功能,以便达到最终结果

所以,这是顺序版

def train_weights(Xtr, ztr, Xte, zte):
    regr = some_model()
    regr.fit(Xtr, ztr)
    error = np.mean((regr.predict(Xte) - zte) ** 2)
    return regr.coef_, error

rnge = range(z_train.shape[0])
weights = []
errors = []
for i in rnge:
    z_dim_tr = z_train[:,i]
    z_dim_te = z_test[:, i]
    weight, error = train_weights(X_train, z_dim_tr, X_test, z_dim_te)
    weights.append(wgts)
    errors.append(error)

所以,我只是从矩阵(训练和测试矩阵)切片 然后将其传递给函数.. 注意,输出的顺序是重量列表中的重量指数...对应于特定的“i”并且对于错误是相同的。

我如何并行化这个?

4 个答案:

答案 0 :(得分:2)

由于这只是一般的并行处理问题,因此您可以使用Pool中的multiprocessing.dummy

由于我没有您的数据集,所以请考虑以下示例。

import multiprocessing
from multiprocessing.dummy import Pool

def test(args):
    a, b = args
    return a

data = [
    (1, 2),
    (2, 3),
    (3, 4),
]

pool = Pool(multiprocessing.cpu_count())

results = pool.map(test, data)

pool.close()
pool.join()

for result in results:
    print(result)

池会创建一定数量的工作进程(在本例中为multiprocessing.cpu_count())。然后,每个工作人员继续执行作业,直到所有作业都已执行。换句话说,map()在所有作业都已执行时首先返回。

总而言之,上面的例子,当调用map()时,它返回的结果列表与给定的顺序相同。因此,最后代码打印12然后3

答案 1 :(得分:1)

查看joblib

https://pythonhosted.org/joblib/parallel.html

  

Joblib提供了一个简单的辅助类来编写并行for循环   使用多处理。核心思想是编写代码   作为生成器表达式执行,并将其转换为并行   计算:

>>> from math import sqrt
>>> [sqrt(i ** 2) for i in range(10)]
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
  

可以使用以下内容分布在2个CPU上:

>>> from math import sqrt
>>> from joblib import Parallel, delayed
>>> Parallel(n_jobs=2)(delayed(sqrt)(i ** 2) for i in range(10))
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

答案 2 :(得分:1)

使用concurrents.futures

可以轻松实现

这是示例代码:

from concurrent.futures.thread import ThreadPoolExecutor

MAX_WORKERS = 20

def train_weights(Xtr, ztr, Xte, zte):
    regr = some_model()
    regr.fit(Xtr, ztr)
    error = np.mean((regr.predict(Xte) - zte) ** 2)
    return regr.coef_, error

def work_done(future):
    weights.append(future.result())

rnge = range(z_train.shape[0])
weights = []
errors = []
for i in rnge:
    z_dim_tr = z_train[:, i]
    z_dim_te = z_test[:, i]
    with ThreadPoolExecutor(MAX_WORKERS) as executor:
        executor.submit(train_weights, X_train, X_test, Xte, z_dim_te).add_done_callback(work_done)

这里执行程序返回它提交的每个任务的未来。请记住,如果您使用add_done_callback()完成的任务从线程返回到主线程(这将阻止您的主线程),如果您真的想要真正的并行性,那么您应该等待未来的对象单独。这是代码片段。

futures = []
for i in rnge:
    z_dim_tr = z_train[:, i]
    z_dim_te = z_test[:, i]
    with ThreadPoolExecutor(MAX_WORKERS) as executor:
        futures.append(executor.submit(train_weights, X_train, X_test, Xte, z_dim_te))

wait(futures)

for succeded, failed in futures:
    # work with your result here
    if succeded:
        weights.append(succeded.result())
    if failed:
        errors.append(failed.result())

答案 3 :(得分:0)

这是使用Ray并行化代码的一种方法。使用Ray的一些优点

  • 大数据将存储在共享内存中,并且可以由多个工作人员访问(以只读方式),因此工作人员无需创建自己的数据副本。
  • 相同的代码将在一台或多台计算机上运行。

Ray是用于编写并行和分布式Python的库。

import numpy as np
import ray

ray.init()

z_train = np.random.normal(size=(100, 30))
z_test = np.random.normal(size=(50, 30))


@ray.remote(num_return_vals=2)
def train_weights(ztr, zte):
    # Fit model.
    predictions = np.random.normal(size=zte.shape[0])
    error = np.mean((predictions - zte) ** 2)
    coef = np.random.normal()
    return coef, error


weight_ids = []
error_ids = []
for i in range(z_train.shape[1]):
    z_dim_tr = z_train[:, i]
    z_dim_te = z_test[:, i]
    weight_id, error_id = train_weights.remote(z_dim_tr, z_dim_te)
    weight_ids.append(weight_id)
    error_ids.append(error_id)

weights = ray.get(weight_ids)
errors = ray.get(error_ids)

您可以在Ray documentation中阅读更多内容。请注意,我是Ray开发人员之一。