Python多处理-池中的进程数是否会因错误而减少?

时间:2019-03-06 14:05:52

标签: python python-3.x parallel-processing multiprocessing python-multiprocessing

代码:

1
3
5
9
11
7
13
15
17
19

打印:

multiprocessing.pool.RemoteTraceback

将池中的进程数增加到3或4将打印所有奇数(可能是乱序):

ValueError: 1

从5开始,则显示所有1-19范围。那么这里发生了什么?多次失败后进程是否崩溃?

这当然是一个玩具示例,但是它来自我遇到的一个实际代码问题-使多处理池运行了几天,使cpu的使用率稳定下降,就好像某些进程被杀死了(请注意,cpu利用率下降了) 03/04和03/06,尽管仍有许多任务要运行):

cpu utilization

当代码终止时,它向我展示了一个(并且这里只有一个,而过程还有更多)FROM microsoft/dotnet:sdk AS build-env WORKDIR /app # Copy csproj and restore as distinct layers COPY *.csproj ./ RUN dotnet restore # Copy everything else and build COPY . ./ RUN dotnet publish -c release -o out # ENV ASPNETCORE_ENVIRONMENT Development # Build runtime image FROM microsoft/dotnet:aspnetcore-runtime WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "test.dll"] -奖励问题是此回溯是随机的吗?在此玩具示例中,通常为version: '3.0' services: db: image: mysql:latest command: --lower_case_table_names=1 environment: MYSQL_DATABASE: test MYSQL_USER: test MYSQL_ROOT_PASSWORD: test volumes: - dbdata:/var/lib/mysql - _MySQL_Init_Script:/docker-entrypoint-initdb.d restart: always onlinesm.logs: image: test build: context: . ports: - "8080:80" volumes: dbdata: {} _MySQL_Init_Script : {} ,但有时还会出现其他数字。多处理程序是否保留了崩溃的第一个进程的第一个回溯?

2 个答案:

答案 0 :(得分:2)

在一个窗口中使用watch ps aux进行快速实验,在另一个窗口中使用您的代码似乎表明,不,异常不会使子进程崩溃。

作为地图/星图操作基础的MapResult对象仅收集第一个异常,如果任何作业因异常而失败,则将整个地图作业视为失败。

(发送给每个工人进行工作的工作量取决于chunksize和朋友的.map()参数。)

如果您希望对异常有更强的适应性,则可以使用.apply_async()

import multiprocessing
import os

def _process(m):
    if m % 2 == 0:
        raise ValueError('I only work on odd numbers')
    return m * 8


if __name__ == '__main__':
    args_list = list(range(1, 20))
    with multiprocessing.Pool(2) as p:
        params_and_jobs = [((arg,), p.apply_async(_process, (arg,))) for arg in args_list]
        for params, job in params_and_jobs:
            job.wait()
            # regularly you'd use `job.get()`, but it would `raise` the exception,
            # which is not suitable for this example, so we dig in deeper and just use
            # the `._value` it'd return or raise:
            print(params, type(job._value), job._value)

输出

(1,) <class 'int'> 8
(2,) <class 'ValueError'> I only work on odd numbers
(3,) <class 'int'> 24
(4,) <class 'ValueError'> I only work on odd numbers
(5,) <class 'int'> 40
(6,) <class 'ValueError'> I only work on odd numbers
(7,) <class 'int'> 56
(8,) <class 'ValueError'> I only work on odd numbers
(9,) <class 'int'> 72
(10,) <class 'ValueError'> I only work on odd numbers
(11,) <class 'int'> 88
(12,) <class 'ValueError'> I only work on odd numbers
(13,) <class 'int'> 104
(14,) <class 'ValueError'> I only work on odd numbers
(15,) <class 'int'> 120
(16,) <class 'ValueError'> I only work on odd numbers
(17,) <class 'int'> 136
(18,) <class 'ValueError'> I only work on odd numbers
(19,) <class 'int'> 152

答案 1 :(得分:2)

不,只是整个任务崩溃,而不是过程本身。在您的玩具示例中观察到的行为可以用工人数量和可迭代长度的组合得到的块大小来解释。当您从here获取函数calc_chunksize_info时,您会看到结果块大小的差异:

calc_chunksize_info(n_workers=2, len_iterable=20)
# Chunkinfo(n_workers=2, len_iterable=20, n_chunks=7, chunksize=3, last_chunk=2)

calc_chunksize_info(n_workers=5, len_iterable=20)
# Chunkinfo(n_workers=5, len_iterable=20, n_chunks=20, chunksize=1, last_chunk=1) 

如果块大小大于1,则一旦第一个taskel引发异常,任务中所有未触及的"taskels" (1. Definitions: Taskel)也会丢失。直接在目标函数中处理可预期的异常,或编写其他包装以进行错误处理以防止这种情况。

  

当代码终止时,它向我展示了一个multiprocessing.pool.RemoteTraceback(唯一的一个,这里有多个进程),额外的问题是回溯是随机的吗?在此玩具示例中,通常为ValueError:1,但有时还会出现其他数字。多处理程序是否保留了崩溃的第一个进程的第一个回溯?

工作进程从共享队列中获取任务。从队列中读取是顺序的,因此任务1将始终在任务2之前读取。尽管如此,在工作人员中准备好结果的顺序是不可预测的。有很多与硬件和操作系统相关的因素在起作用,所以是的,回溯是随机的,因为结果的顺序是随机的,因为(字符串化的)回溯是将结果发送回父级的一部分。结果也通过共享队列发送回去,并且Pool内部处理返回的任务JIT。万一任务返回失败,则将整个作业标记为不成功,并丢弃进一步到达的任务。一旦作业中的所有任务都返回,只有第一个检索到的异常在父级中重新引发。