-1

我有以下函数来计算激光束在腔中的传播。它取决于存储在名为 dict 的许多参数core_data,这是一个基本参数集。

def propagate(N, core_data, **ddata):
    cd = copy.deepcopy(core_data)  # use initial configuration
    cd.update(ddata)  # update with data I want to change
    cavity = get_new_cavity(cd)  # get new cavity object
    P = []
    for i in range(N):
        cavity.evolve(1)
        P.append(cavity.get_power())
    return P

如果我想改变一个参数并查看它对激光的影响,我可以调用这个函数,例如

P0 = propagate(1000, core_data, L1=1.2, M5=17)

这很好用。

现在,我将编写一个函数,将该函数传递给 a ProcessPoolExecutor,并使用相同的键对值**ddata进行迭代。例如,它应该像这样工作(更简单的例子):

propagate_parallel(1000, core_data,
                   L1=np.linspace(1, 2, 2),
                   M5=np.linspace(16, 17, 2))

然后应该并行执行此操作:

propagate(1000, core_data, L1=1, M5=16)
propagate(1000, core_data, L1=1, M5=17)
propagate(1000, core_data, L1=2, M5=16)
propagate(1000, core_data, L1=2, M5=17)

这样的事情适用于我的情况:

xrng = np.linspace(110e-30, 150e-30, Nx)
yrng = np.linspace(6.6e-9, 6.7e-9, Ny)

futures = []
with confu.ProcessPoolExecutor(max_workers=Ncores) as pool:
    for y, x in it.product(yrng, xrng):
        futures.append(pool.submit(propagate, RTs=1000,
                                   core_data=core_data,
                                   gdd_dm=x, dwl_filt=y))

问题是这不灵活,我不能把它变成一个很好的函数,如上所述。它应该是一个可以这样调用的函数来重现上面的代码:

propagate_parallel(1000, core_data, gdd_dm=xrng, dwl_filt=yrng)

我将如何通过相应键**ddata的迭代值传递键?

仅供参考,我用过:

import numpy as np
import concurrent.futures as confu
import itertools as it
4

2 回答 2

0

您正在寻找迭代笛卡尔积。

这是一种迭代笛卡尔的方法。

from itertools import product
import numpy as np

L1=np.linspace(1, 2, 2)
M5=np.linspace(16, 17, 2)
dconf = dict(data=5)
size = L1.size
loop_size = size**2

def propagate(N, data, modifiers):
    data.update(modifiers)
    out = []
    for i in range(N):
        out.append('%s : %s : %s : %s'%(i, *data.values()))
    return out

mod = (dict(L1=i, M5=j) for i, j in product(L1, M5))
m = map(propagate, np.arange(2, 2+loop_size), (dconf,)*loop_size, mod)

for outer in m:
    for inner in outer:
        print(inner)

这你可以适应你的代码,如果你真的需要并行化(这意味着在核心之间的信息拆分方面),可以看看 Dask。

希望这足以让你继续前进。

编辑:您的问题实际上很难确定。您的问题真的是如何实现简单的“函数调用”吗?我想一个答案就是制作一个包装功能,比如......

def propagate(N, data, modifiers):
    ...

def call_propagate(N, data, L1_, M5_):
    mod = ...
    m = map(...
    return m

for outer in call_propagate(1000, dconf, L1, M5)
    for inner in outer:
        print(inner)
于 2019-01-18T23:41:59.043 回答
0

我想我不知何故被阻止了......我一直在思考如何保留变量名(例如L1)并将其作为变量传递给另一个函数。

@ahead87:您的第一句话已经让我畅通无阻,我意识到这**data可以通过字典简单地处理。所以,最后,我只需要将输入字典转换为下一个函数的字典列表,就像这样(剪掉一些不相关的部分):

def propagate_parallel(RTs, cav_data, **ddata):
    keys = list(ddata.keys())
    values = list(ddata.values())
    futures = []
    res = []
    with confu.ProcessPoolExecutor(max_workers=32) as pool:
        for i in it.product(*values):
            futures.append(pool.submit(propagate, RTs=RTs,
                                       cav_data=cav_data,
                                       **dict(zip(keys, list(i)))))
    for fut in futures:
        res.append(fut)
    return res

最后,我想我终于明白**kwargs了,它可以作为字典处理。谢谢!

于 2019-01-19T14:35:55.007 回答