如何正确实现apply_async进行数据处理?

时间:2019-02-11 16:02:52

标签: python multiprocessing

我不熟悉使用并行处理进行数据分析。我有一个相当大的数组,我想将一个函数应用于所述数组的每个索引。

这是我到目前为止的代码:

import numpy as np
import statsmodels.api as sm
from statsmodels.regression.quantile_regression import QuantReg
import multiprocessing
from functools import partial

def fit_model(data,q):
    #data is a 1-D array holding precipitation values
    years = np.arange(1895,2018,1)
    res = QuantReg(exog=sm.add_constant(years),endog=data).fit(q=q)
    pointEstimate = res.params[1] #output slope of quantile q
    return pointEstimate

#precipAll is an array of shape (1405*621,123,12) (longitudes*latitudes,years,months)
#find all indices where there is data
nonNaN = np.where(~np.isnan(precipAll[:,0,0]))[0] #481631 indices
month = 4

#holder array for results
asyncResults = np.zeros((precipAll.shape[0])) * np.nan
def saveResult(result,pos):
    asyncResults[pos] = result

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=20) #my server has 24 CPUs
    for i in nonNaN:
        #use partial so I can also pass the index i so the result is
        #stored in the expected position

        new_callback_function = partial(saveResult, pos=i)
        pool.apply_async(fit_model, args=(precipAll[i,:,month],0.9),callback=new_callback_function)

    pool.close()
    pool.join()

当我运行它时,我花了比我根本不使用多处理时间更长的时间才将其停止。函数fit_model大约为0.02秒,那么与apply_async相关联的突出会导致速度变慢吗?完成此处理后,将数据绘制到地图上时,我需要保持结果的顺序。任何关于我需要改进的地方的想法,将不胜感激!

1 个答案:

答案 0 :(得分:0)

如果需要使用多处理模块,则可能需要将更多行一起批处理到分配给工作池的每个任务中。但是,对于您正在做的事情,由于其Ray,我建议您尝试一下efficient handling of large numerical data

import numpy as np
import statsmodels.api as sm
from statsmodels.regression.quantile_regression import QuantReg
import ray

@ray.remote
def fit_model(precip_all, i, month, q):
    data = precip_all[i,:,month]
    years = np.arange(1895, 2018, 1)
    res = QuantReg(exog=sm.add_constant(years), endog=data).fit(q=q)
    pointEstimate = res.params[1]
    return pointEstimate

if __name__ == '__main__':
    ray.init()

    # Create an array and place it in shared memory so that the workers can
    # access it (in a read-only fashion) without creating copies.
    precip_all = np.zeros((100, 123, 12))
    precip_all_id = ray.put(precip_all)

    result_ids = []
    for i in range(precip_all.shape[0]):
        result_ids.append(fit_model.remote(precip_all_id, i, 4, 0.9))

    results = np.array(ray.get(result_ids))

一些注释

上面的示例是开箱即用的,但是请注意,我稍微简化了逻辑。特别是,我删除了NaN的处理。

在具有4个物理核心的笔记本电脑上,这大约需要4秒钟。如果改用20个内核,并使数据增大9000倍,我希望它花费大约7200秒,这是一个相当长的时间。一种加快速度的可能方法是使用更多计算机或在每次对fit_model的调用中处理多行,以分摊一些开销。

上面的示例实际上将整个precip_all矩阵传递给每个任务。很好,因为每个fit_model任务仅具有对存储在共享内存中的矩阵副本的读取访问权限,因此不需要创建自己的本地副本。对ray.put(precip_all)的调用一次将数组放置在共享内存中。

大约differences between Ray and Python multiprocessing。注意,我正在帮助开发Ray。