【问题标题】:How to fail fast with multiprocessing?如何通过多处理快速失败?
【发布时间】:2019-12-01 12:38:08
【问题描述】:

以下代码是我在超参数函数中抛出Exception 时第一次尝试快速失败。

不幸的是,在调用者收到异常之前,首先处理了整个数据。

如果在被调用的函数中发生错误,我该怎么做才能立即终止整个过程(这样我就可以更快地纠正我的编码错误等,而不必等到所有不同的参数组合都已处理完毕/优化)?

代码:

from sklearn.model_selection import ParameterGrid
from multiprocessing import Pool
from enum import Enum

var1 = 'var1'
var2 = 'var2'
abc = [1, 2]
xyz = list(range(1_00_000))
pg = [{'variant': [var1],
       'abc': abc,
       'xyz': xyz, },
      {'variant': [var2],
       'abc': abc, }]
parameterGrid = ParameterGrid(pg)
myTemp = list(parameterGrid)

print('len(parameterGrid):', len(parameterGrid))


def myFunc(myParam):
    if myParam['abc'] == 1:
        raise ValueError('error thrown')
    print(myParam)


pool = Pool(1)
myList = pool.map(myFunc, parameterGrid)

结果:

len(parameterGrid): 200002
{'abc': 2, 'variant': 'var1', 'xyz': 2}
{'abc': 2, 'variant': 'var1', 'xyz': 3}
{'abc': 2, 'variant': 'var1', 'xyz': 4}
{'abc': 2, 'variant': 'var1', 'xyz': 5}
{'abc': 2, 'variant': 'var1', 'xyz': 6}
.
.
.
{'abc': 2, 'variant': 'var1', 'xyz': 99992}
{'abc': 2, 'variant': 'var1', 'xyz': 99993}
{'abc': 2, 'variant': 'var1', 'xyz': 99994}
{'abc': 2, 'variant': 'var1', 'xyz': 99995}
{'abc': 2, 'variant': 'var1', 'xyz': 99996}
{'abc': 2, 'variant': 'var1', 'xyz': 99997}
{'abc': 2, 'variant': 'var1', 'xyz': 99998}
{'abc': 2, 'variant': 'var1', 'xyz': 99999}
ValueError: error thrown

【问题讨论】:

标签: python python-multiprocessing hyperparameters


【解决方案1】:

紧急终止整个Pool进程(希望您需要这样的条件来进行测试):

...
def myFunc(myParam):
    if myParam['abc'] == 1:
        print('error occurred')
        pool.terminate()    # accessed globally
    print(myParam)

if __name__ == '__main__':
    pool = Pool(1)
    myList = pool.map(myFunc, parameterGrid)

https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.Pool.terminate

【讨论】:

  • 我可能遗漏了一些东西,但是 # 全局访问:如何?使用 start 方法spawn 不会在工作进程中创建池。对于forkforkserver,有一个未完全初始化的池,未分配给worker 中的名称pool(或任何其他名称)。
  • @shmee,了解子进程在条件if __name__ == '__main__': 下会发生什么情况在 Unix 上使用 fork start 方法,子进程可以使用在父进程中创建的共享资源全球资源。但这对于 Unix 来说更重要(实际上我不考虑 Windows)
  • @shmee,这里有一个类似的话题stackoverflow.com/a/36962624/3185459
  • 我不确定你的例子是否适用。工人在池的初始化期间被分叉。将池对象分配给名称 pool 发生在池的 __init__ 方法完成之后,此时工人已经活着。您链接的答案的第一个代码示例中的 Event 对象在工作程序中可用,因为它们是在池实例化之前创建的。如果将它们的实例化移动到池的实例化之后,在函数中使用它们会引发 NameError,就像在此处使用 pool 一样。
  • 在该答案的第二个代码示例中,在池中调用 terminate 的函数作为回调传递。这在主进程中执行,因此在这种情况下,池已完全初始化并分配给相应的名称。
【解决方案2】:

正如我所见,并未处理整个数据。只有 case 'abc' = 2 它通过了。一旦 myFunc 得到一个 'abc' = 2 的参数,它就会抛出一个异常。看起来不错,不是吗? 您可以在运行地图之前检查所有参数网格。它只留下有效/适合您的值

myTemp_2 = filter(lambda x: x['abc'] != 1, myTemp)

它只留下适合你的值

【讨论】:

    猜你喜欢
    • 2021-11-06
    • 1970-01-01
    • 2017-09-17
    • 2019-09-07
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多