다중 처리:청크사이즈 이면의 논리 이해
를 결정하는 입니까?chunksize 방에대주장과 같은 에 대한 multiprocessing.Pool.map() 더.map()메소드는 기본 청크 크기(아래 그림 참조)에 대해 임의 휴리스틱을 사용하는 것 같습니다. 무엇이 그러한 선택에 동기를 부여하고 특정 상황/상황에 기초하여 더 사려 깊은 접근법이 있습니까?
예 - 예를 들어 다음과 같습니다.
-
iterable.map()은 ~개의 원소를 가지고 있습니다; 대만개 1,500의 요소포함합니다최를▁that다;최니▁has포함. - 코어가 24개인 시스템에서 작업하고 내부에서 기본값 사용
multiprocessing.Pool().
저의 순진한 생각은 24명의 노동자들에게 각각 같은 크기의 덩어리를 주는 것입니다.15_000_000 / 2462 천 5 명. 큰작업자를 합니다.큰 덩어리는 모든 작업자를 충분히 활용하면서 매출액/오버헤드를 줄여야 합니다.그러나 이것은 각 근로자에게 대량의 배치를 제공하는 것에 대한 몇 가지 잠재적인 단점을 놓치고 있는 것처럼 보입니다.이것은 불완전한 그림이고, 제가 무엇을 놓쳤습니까?
제 질문의 일부는 다음과 같은 경우의 기본 논리에서 비롯됩니다.chunksize=None 다.map()그리고..starmap()호출, 다음과 같이 표시됩니다.
def _map_async(self, func, iterable, mapper, chunksize=None, callback=None,
error_callback=None):
# ... (materialize `iterable` to list if it's an iterator)
if chunksize is None:
chunksize, extra = divmod(len(iterable), len(self._pool) * 4) # ????
if extra:
chunksize += 1
if len(iterable) == 0:
chunksize = 0
의 논리는 divmod(len(iterable), len(self._pool) * 4)이는 청크 크기가 다음에 더 가깝다는 것을 의미합니다.15_000_000 / (24 * 4) == 156_250곱셈의 의도는 무엇입니까?len(self._pool)4시까지?
이것은 결과 청크 크기를 위의 "순수한 논리"보다 4배 더 작은 요소로 만듭니다. 이 논리는 반복 가능한 길이를 작업자 수로 나누는 것으로 구성됩니다.pool._pool.
마지막으로, 파이썬 문서의 이 스니펫도 있습니다..imap()그것은 나의 호기심을 더욱 자극합니다.
그
chunksize는 인가사인동일다니합수에서 .map()방법. 큰값사매는을한우경에 큰하는 매우 긴chunksize기본값인 1을 사용하는 것보다 훨씬 빠르게 작업을 완료할 수 있습니다.
도움이 되지만 너무 높은 수준의 관련 답변:파이썬 다중 처리: 큰 청크 크기가 느린 이유는 무엇입니까?
단답형
풀의 청크 크기 알고리즘은 휴리스틱입니다.풀의 방법에 입력하려는 모든 상상할 수 있는 문제 시나리오에 대한 간단한 해결책을 제공합니다.따라서 특정 시나리오에 맞게 최적화할 수 없습니다.
알고리즘은 임의로 반복 가능한 부분을 순진한 접근법보다 약 4배 많은 청크로 나눕니다.청크가 많을수록 오버헤드는 증가하지만 스케줄링 유연성은 증가합니다.이 대답이 어떻게 나타나는지, 이것은 평균적으로 더 높은 작업자 활용률로 이어지지만 모든 경우에 대해 더 짧은 전체 계산 시간을 보장하지는 않습니다.
"알게 되어 기쁩니다."라고 생각할 수도 있습니다. "하지만 이것을 아는 것이 구체적인 다중 처리 문제를 해결하는 데 어떻게 도움이 될까요?"글쎄, 그렇지 않아요.더 솔직한 단답은 "단답은 없다", "다중 처리는 복잡하다", "다중 처리는 다르다"입니다.관찰된 증상은 유사한 시나리오에서도 서로 다른 루트를 가질 수 있습니다.
이 답변은 풀의 일정 블랙박스를 보다 명확하게 파악하는 데 도움이 되는 기본 개념을 제공하려고 합니다.또한 청크 크기와 관련된 잠재적인 절벽을 인식하고 피할 수 있는 몇 가지 기본적인 도구를 제공하려고 합니다.
목차.
제1부
- 정의들
- 병렬화 목표
- 병렬화 시나리오
- 청크 크기 > 1의 위험
- 풀의 청크 크기-알고리즘
알고리즘 효율성 정량화
6.1 모델
6.2 병렬 일정
6.3 효율성
6.3.1 절대유통효율(ADE)
6.3.2 상대 분포 효율(RDE)
- 순진함 vs.풀의 청크 크기-알고리즘
- 리얼리티 체크
- 결론
우선 몇 가지 중요한 용어를 명확히 할 필요가 있습니다.
정의
청크
▁share다▁a▁a의 몫입니다.iterable.-pool-sublished 에 된 어떤 를 가져올 수 입니다.이 답변의 주제는 청크 크기를 계산하는 방법과 청크 크기가 어떤 영향을 미칠 수 있는지에 대한 것입니다.
작업
작업 프로세스에서 데이터 측면에서 작업의 물리적 표현은 아래 그림에서 확인할 수 있습니다.
그림은 다음에 대한 호출의 예를 보여줍니다.pool.map()되며, 드코 라표며되가다, 져옵니에서시에서 .multiprocessing.pool.workerfunction,는 수서, 여기작읽에서 .inqueue짐을 풉니다. worker는 의기인주기다니능입요의 인 주요 입니다.MainThread수영장 노동자 과정의. 그func은 -pool-pool-pool과만 합니다.func- 에 - 위한 에 variableworker은 -function은 -function과 같은 에 사용됩니다.apply_async에 대해서도imap와 함께chunksize=1▁a▁thechunksize processing-function -함수 매개변수func가 될 입니다.mapstar또는starmapstar). 이가 지정한 것을 func-itable의 전송된 청크의 모든 요소에 대한 매개 변수(--> "map-message").이 작업에 걸리는 시간은 작업을 작업 단위로 정의하기도 합니다.
태스켈
한 청크의 전체 처리에 대한 "태스크"라는 단어의 사용은 다음과 같은 코드에 의해 일치합니다.multiprocessing.pool사용자가 지정한 단일 통화 방법이 없습니다.func청크의 한 요소를 인수로 사용하여 참조해야 합니다. 지정 충돌에서 (이지충서예발혼는란방을위기해지하하생에돌정름예▁of▁to위:(해▁(think▁emerging기하▁conflicts:maxtasksperchild는 -pool의 파라미터입니다.__init__-taskel), 이 답변은 태스크 내의 단일 작업 단위를 태스켈이라고 합니다.
태스켈(태스킹 + 요소에서)은 태스크 내에서 가장 작은 단위의 작업입니다.이는 다음과 같이 지정된 기능의 단일 실행입니다.
func매 변Pool전송된 청크의 단일 요소에서 가져온 인수를 사용하여 호출되는 -dump.작업은 다음과 같이 구성됩니다.chunksize태스켈
병렬화 오버헤드(PO)
PO는 프로세스 간 통신(IPC)을 위한 Python 내부 오버헤드 및 오버헤드로 구성됩니다.Python 내의 작업별 오버헤드는 작업과 결과를 패키징 및 언팩하는 데 필요한 코드와 함께 제공됩니다.IPC 오버헤드는 스레드의 필요한 동기화 및 서로 다른 주소 공간 간의 데이터 복사와 함께 제공됩니다(부모 -> 대기열 -> 자식).IPC 오버헤드의 양은 OS, 하드웨어 및 데이터 크기에 따라 달라지므로 영향에 대한 일반화가 어렵습니다.
병렬화 목표
멀티프로세싱을 사용할 때 우리의 전반적인 목표는 (분명히) 모든 작업에 대한 총 처리 시간을 최소화하는 것입니다.이 전체적인 목표를 달성하기 위해서는 하드웨어 리소스 활용률을 최적화하는 것이 기술적 목표입니다.
기술 목표를 달성하기 위한 몇 가지 중요한 하위 목표는 다음과 같습니다.
우선 병렬화를 위해 지불해야 하는 PO를 회수하기 위해 작업이 충분히 무겁고(집약적) 작업이 필요합니다.PO의 관련성은 태스켈당 절대 계산 시간이 증가함에 따라 감소합니다.즉, 문제에 대한 태스켈당 절대 계산 시간이 클수록 PO를 줄일 필요성이 줄어듭니다.계산에 태스켈당 몇 시간이 걸릴 경우 IPC 오버헤드는 비교해 볼 때 무시할 수 있습니다.여기서 가장 중요한 관심사는 모든 작업이 분산된 후 작업자 프로세스가 유휴 상태가 되는 것을 방지하는 것입니다.모든 코어를 로드 상태로 유지한다는 것은 가능한 한 병렬화하고 있다는 것을 의미합니다.
병렬화 시나리오
다중 처리와 같은 방법에 대한 최적의 청크 크기 인수를 결정하는 요인.풀.map()
문제가 되는 주요 요인은 단일 태스켈에 따라 계산 시간이 얼마나 달라질 수 있는지입니다.즉, 최적의 청크 크기에 대한 선택은 작업el당 계산 시간에 대한 변동 계수(CV)에 의해 결정됩니다.
이 변동의 범위에서 다음과 같은 척도의 두 극단적인 시나리오는 다음과 같습니다.
- 모든 태스켈은 정확히 같은 계산 시간이 필요합니다.
- 태스켈을 완료하는 데 몇 초 또는 며칠이 걸릴 수 있습니다.
더 나은 기억력을 위해 이 시나리오들을 다음과 같이 언급하겠습니다.
- 고밀도 시나리오
- 와이드 시나리오
고밀도 시나리오
고밀도 시나리오에서는 필요한 IPC와 컨텍스트 전환을 최소화하기 위해 모든 태스켈을 한 번에 배포하는 것이 바람직합니다.즉, 작업자 프로세스 수만큼의 청크만 생성해야 합니다.위에서 이미 언급한 바와 같이, PO의 가중치는 태스켈당 계산 시간이 짧을수록 증가합니다.
또한 처리량을 극대화하기 위해 모든 작업이 처리될 때까지 모든 작업자 프로세스를 사용합니다(공회전 작업자 없음).이를 위해 분산 청크의 크기는 같거나 이에 가까워야 합니다.
와이드 시나리오
광범위한 시나리오의 주요 예는 결과가 빠르게 수렴되거나 계산에 며칠이 아닌 몇 시간이 걸릴 수 있는 최적화 문제입니다.일반적으로 이러한 경우 작업에 "가벼운 태스켈"과 "무거운 태스켈"이 어떤 혼합물을 포함할지 예측할 수 없기 때문에 한 번에 작업 배치에 너무 많은 태스켈을 배포하는 것은 바람직하지 않습니다.한 번에 가능한 것보다 적은 수의 태스켈을 배포하는 것은 스케줄링의 유연성을 증가시키는 것을 의미합니다.이는 모든 코어의 높은 활용률이라는 하위 목표를 달성하기 위해 필요합니다.
한다면Pool메소드는 기본적으로 조밀 시나리오에 완전히 최적화되어 있으며, 와이드 시나리오에 더 가까운 모든 문제에 대해 점점 더 차선의 타이밍을 만듭니다.
청크 크기 > 1의 위험
풀 방식으로 전달하고자 하는 와이드 시나리오-itable의 단순화된 유사 코드 예제를 생각해 보십시오.
good_luck_iterable = [60, 60, 86400, 60, 86400, 60, 60, 84600]
실제 값 대신 필요한 계산 시간을 1분 또는 1일로 단순화하기 위해 초 단위로 보는 것처럼 가장합니다. process(4개의 와 4개의 process(4개의 core)가합니다.chunksize으로 설정됨2순서가 유지되므로 작업자에게 보내는 청크는 다음과 같습니다.
[(60, 60), (86400, 60), (86400, 60), (60, 84600)]
작업자가 충분하고 계산 시간이 충분히 길기 때문에 모든 작업자 프로세스는 우선 작업해야 할 부분을 얻게 될 것입니다.(작업을 빨리 완료하는 경우에는 그렇지 않습니다.)또한 전체 처리에는 약 86400+60초가 소요됩니다. 이는 인공 시나리오에서 청크의 총 계산 시간이 가장 높고 청크를 한 번만 배포하기 때문입니다.
이제 이전의 반복 가능한 항목과 비교하여 하나의 요소만 위치를 전환하는 이 반복 가능한 항목에 대해 생각해 보십시오.
bad_luck_iterable = [60, 60, 86400, 86400, 60, 60, 60, 84600]
...및 해당 청크:
[(60, 60), (86400, 86400), (60, 60), (60, 84600)]
우리의 반복 가능한 정렬이 우리의 총 처리 시간(86400+86400)을 거의 두 배로 늘린 것은 정말 불행한 일입니다!악의적인 (86400, 86400)-청크를 받는 근로자는 이미 (60, 60)-청크를 마친 유휴 근로자 중 한 명에게 업무의 두 번째 무거운 태스켈이 분배되는 것을 막고 있습니다.만약 우리가 그렇게 불쾌한 결과를 감수하지 않을 것이 분명합니다.chunksize=1.
이것은 더 큰 덩어리의 위험입니다.청크 크기가 클수록 스케줄링 유연성을 통해 오버헤드를 줄일 수 있습니다. 위와 같은 경우에는 좋지 않습니다.
6장에서 우리가 어떻게 볼 것인지. 알고리즘 효율성 정량화, 청크 크기가 클수록 고밀도 시나리오에 대한 최적의 결과가 나올 수 있습니다.
풀의 청크 크기-알고리즘
아래에는 소스 코드 안에 알고리즘의 약간 수정된 버전이 있습니다.보시는 바와 같이 아래 부분을 잘라내어 그것을 계산하는 함수로 포장했습니다.chunksize외견상의 의론저도 교체했습니다.4factor 및 을 수행했습니다.len()전화가 걸려오는 전화.
# mp_utils.py
def calc_chunksize(n_workers, len_iterable, factor=4):
"""Calculate chunksize argument for Pool-methods.
Resembles source-code within `multiprocessing.pool.Pool._map_async`.
"""
chunksize, extra = divmod(len_iterable, n_workers * factor)
if extra:
chunksize += 1
return chunksize
우리 모두가 같은 생각을 하고 있다는 것을 확실히 하기 위해, 여기에.divmod실행:실행:
divmod(x, y)는 를반하내함수다니입장는환을 반환하는 입니다.(x//y, x%y).x // y바닥 분할이며, 아래쪽 반올림된 몫을 반환합니다.x / y,하는 동안에x % y 를반는모작듈업다니입로환하지▁▁the에서 나머지를 반환하는 입니다.x / y그러므로 예를 들어. divmod(10, 3)아온다를 합니다.(3, 1).
, 이신▁at▁you때볼▁now.chunksize, extra = divmod(len_iterable, n_workers * 4)은 알 것입니다.n_workers에 제수가 있습니다.y안에x / y곱셈을 사용한 값을 계산합니다.4을 통해 더 이상 조정하지 않고.if extra: chunksize +=1나중에, 초기 청크 크기가 최소 4배 더 작아집니다(의 경우len_iterable >= n_workers * 4 그렇지 않을 때보다.
곱셈의 효과를 보기 위해4중간 청크 크기 결과에서 이 함수를 고려합니다.
def compare_chunksizes(len_iterable, n_workers=4):
"""Calculate naive chunksize, Pool's stage-1 chunksize and the chunksize
for Pool's complete algorithm. Return chunksizes and the real factors by
which naive chunksizes are bigger.
"""
cs_naive = len_iterable // n_workers or 1 # naive approach
cs_pool1 = len_iterable // (n_workers * 4) or 1 # incomplete pool algo.
cs_pool2 = calc_chunksize(n_workers, len_iterable)
real_factor_pool1 = cs_naive / cs_pool1
real_factor_pool2 = cs_naive / cs_pool2
return cs_naive, cs_pool1, cs_pool2, real_factor_pool1, real_factor_pool2
chunksize (nive size)를 합니다.cs_naive() 및 청 크 크 알 즘 의 단 청 크 크 기 계 첫 리 고 기 풀 의 ▁) 기 ▁thecs_pool1풀 (), 를 포함합니다.cs_pool2). 또한 실제 요인을 계산합니다. rf_pool1 = cs_naive / cs_pool1그리고.rf_pool2 = cs_naive / cs_pool2이를 통해 단순하게 계산된 청크 크기가 풀의 내부 버전보다 몇 배 더 큰지 알 수 있습니다.
아래에는 이 함수의 출력으로 생성된 두 개의 그림이 나와 있습니다.왼쪽 그림은 다음에 대한 청크 크기를 보여줍니다.n_workers=4의 상당한 까지.500은 오쪽그다대값보다니여줍을의 값을 .rf_pool1 수 있는 길이 을참수있길이로는로▁for길이▁it.16은 진짜요은이 됩니다.>=4(의 경우)len_iterable >= n_workers * 4은 )입니다.7 수 있는 길이 동안28-31그것은 원래의 요인으로부터 엄청난 편차입니다.4로됩렴해성가능복반리▁'▁is▁here. 여기서 '는 으로, 에 따라 .여기서 '긴 길이'는 상대적이며 지정된 작업자 수에 따라 달라집니다.
cs_pool1 아직부니다합이 합니다.extra부터 까지의 나머지 값으로 divmod에함된에 .cs_pool2완전한 알고리즘으로부터.
알고리즘은 다음과 같이 진행됩니다.
if extra:
chunksize += 1
이제 경우에 따라 나머지가 있습니다.extra만큼 늘리면 작업에 대해 될 수 . divmod-operation).에서 청크 크기를 1만큼 증가시키는 것이 모든 작업에 대해 효과적일 수는 없습니다.결국, 만약 그렇다면, 시작할 나머지가 없을 것입니다.
아래의 그림에서 볼 수 있는 것처럼, "추가 치료"는 효과가 있습니다, 즉rf_pool2는 제이쪽으모입다니로다모ges로 수렴합니다.4밑에서 4편차가 다소 더 매끄럽습니다. 편 차에 대한 표준 :n_workers=4그리고.len_iterable=500에 짐어떨에서 떨어집니다.0.5233위해서rf_pool10.4115위해서rf_pool2.
결국, 증가하는chunksize1 은 마 지 막 으 전 작 송 크 있 효 갖 니 습 다 가 과 는 만 기 이 업 된 로 니 다 ▁has ▁by , ▁transm ▁has ▁effect ▁of ▁1 ▁1 ▁size ▁a ▁the ▁the 습 ▁that있len_iterable % chunksize or chunksize.
더 흥미롭고 나중에 더 결과적인 추가 처리의 효과를 볼수록 생성된 청크의 수에 대해 관찰할 수 있습니다.n_chunks 반복할 수 된 청크 알고리즘(). 충분히 오랫동안 반복할 수 있도록 풀의 완성된 청크 크기 알고리즘(n_pool2는으로 는 청 수 안 합 화 니 정 다 를 아 래 의 그 크 림 서 에n_chunks == n_workers * 4대조적으로, 순진한 알고리즘(초기 트림 후)은 다음과 같은 알고리즘 사이를 계속 번갈아가며 사용합니다.n_chunks == n_workers그리고.n_chunks == n_workers + 1반복할 수 있는 길이가 길어짐에 따라
아래에는 풀과 순진한 청크 크기 알고리즘에 대한 두 가지 향상된 정보 함수가 있습니다.이러한 기능의 출력은 다음 장에서 필요합니다.
# mp_utils.py
from collections import namedtuple
Chunkinfo = namedtuple(
'Chunkinfo', ['n_workers', 'len_iterable', 'n_chunks',
'chunksize', 'last_chunk']
)
def calc_chunksize_info(n_workers, len_iterable, factor=4):
"""Calculate chunksize numbers."""
chunksize, extra = divmod(len_iterable, n_workers * factor)
if extra:
chunksize += 1
# `+ (len_iterable % chunksize > 0)` exploits that `True == 1`
n_chunks = len_iterable // chunksize + (len_iterable % chunksize > 0)
# exploit `0 == False`
last_chunk = len_iterable % chunksize or chunksize
return Chunkinfo(
n_workers, len_iterable, n_chunks, chunksize, last_chunk
)
의 예상치 못한 모습에 당황하지 마십시오.calc_naive_chunksize_info.extradivmod청크 크기를 계산하는 데 사용되지 않습니다.
def calc_naive_chunksize_info(n_workers, len_iterable):
"""Calculate naive chunksize numbers."""
chunksize, extra = divmod(len_iterable, n_workers)
if chunksize == 0:
chunksize = 1
n_chunks = extra
last_chunk = chunksize
else:
n_chunks = len_iterable // chunksize + (len_iterable % chunksize > 0)
last_chunk = len_iterable % chunksize or chunksize
return Chunkinfo(
n_workers, len_iterable, n_chunks, chunksize, last_chunk
)
알고리즘 효율성 정량화
이제, 우리가 어떻게 산출하는지 본 후에.Pool의 청크 크기 변환은 단순 알고리즘의 출력과 비교했을 때 다르게 보입니다...
- Pool의 접근 방식이 실제로 무언가를 개선하는지 확인하는 방법은 무엇입니까?
- 그리고 이게 정확히 무엇일까요?
이전 장에 나와 있는 것처럼, 반복 가능한 시간이 더 긴(더 많은 수의 태스켈) 경우 풀의 청크 크기 알고리즘은 반복 가능한 시간을 대략적으로 단순한 방법보다 4배 더 많은 청크로 나눕니다.청크가 작으면 작업이 많아지고 작업이 많아지면 병렬화 오버헤드(PO)가 증가합니다. 이 비용은 스케줄링 유연성 향상의 이점과 비교해야 합니다("청크 크기의 위험>1"이라고 함).
다소 분명한 이유로, Pool의 기본 청크 크기 알고리듬은 PO에 비해 스케줄링 유연성을 고려할 수 없습니다.IPC 오버헤드는 OS, 하드웨어 및 데이터 크기에 따라 다릅니다.알고리즘은 우리가 어떤 하드웨어에서 우리의 코드를 실행하는지 알 수 없으며, 태스커가 완료하는 데 얼마나 걸릴지도 모릅니다.모든 가능한 시나리오에 대한 기본 기능을 제공하는 휴리스틱입니다.이는 특정 시나리오에 대해 최적화할 수 없음을 의미합니다.앞에서 언급했듯이 PO는 또한 태스켈당 계산 시간 증가에 대한 관심이 점점 줄어들고 있습니다(음의 상관 관계).
2장의 병렬화 목표를 상기할 때 한 가지 요점은 다음과 같습니다.
- 모든 CPU 프로세서에서 높은 활용률
앞에서 언급한 바와 같이 풀의 청크 크기 알고리즘은 각각 CPU 코어의 활용도와 유휴 작업자 프로세스의 최소화를 개선하려고 시도할 수 있습니다.
에 SO multiprocessing.Pool사용되지 않는 코어/공회전 작업자가 모든 작업자가 바쁠 것으로 예상되는 상황에서 유휴 작업자 작업자 작업자 작업에 대해 궁금해하는 사람들의 질문을 받습니다.이것은 많은 이유를 가질 수 있지만, 작업자 수가 청크 수의 약수가 아닌 경우 밀도가 높은 시나리오(태스클당 동일한 계산 시간)에서도 계산이 끝날 때까지의 공회전 작업자 프로세스는 종종 우리가 수행할 수 있는 관찰입니다.n_chunks % n_workers > 0).
이제 질문은 다음과 같습니다.
청크 크기에 대한 이해를 실제로 관찰된 작업자 활용도를 설명하거나 그러한 측면에서 다른 알고리듬의 효율성을 비교할 수 있는 것으로 어떻게 변환할 수 있습니까?
6.1 모델
여기서 더 깊은 통찰력을 얻으려면 지나치게 복잡한 현실을 관리 가능한 복잡성 수준으로 단순화하고 정의된 경계 내에서 중요성을 유지하는 병렬 계산의 추상화 형태가 필요합니다.이러한 추상화를 모델이라고 합니다.이러한 "병렬화 모델"(PM)의 구현은 데이터가 수집되는 경우 실제 계산과 마찬가지로 작업자 매핑 메타데이터(타임 스탬프)를 생성합니다.모델 생성 메타 데이터를 사용하면 특정 제약 조건에서 병렬 계산의 메트릭을 예측할 수 있습니다.
여기서 정의된 PM 내의 두 가지 하위 모델 중 하나는 DM(Distribution Model)입니다. DM은 각 청크 크기 알고리즘, 작업자 수, 입력 가능한 작업량(태스켈 수) 및 계산 지속 시간 외에 다른 요소가 없는 경우 병렬 작업자에 대해 원자 단위(태스켈)가 어떻게 분배되는지 설명합니다.즉, 어떠한 형태의 오버헤드도 포함되지 않습니다.
완전한 PM을 얻기 위해 DM은 다양한 형태의 병렬화 오버헤드(PO)를 나타내는 오버헤드 모델(OM)로 확장됩니다.이러한 모델은 각 노드에 대해 개별적으로 보정해야 합니다(하드웨어, OS 종속성).OM에서 얼마나 많은 형태의 오버헤드가 표시되는지는 열려 있으므로 복잡도가 다른 여러 OM이 존재할 수 있습니다.구현된 OM에 필요한 정확도 수준은 특정 계산을 위한 PO의 전체 가중치에 의해 결정됩니다.태스켈이 짧을수록 PO의 가중치가 높아지므로 PE(Parallelization Efficiency)를 예측하려면 더 정확한 OM이 필요합니다.
6.2 병렬 공정표(PS)
병렬 일람표는 병렬 계산의 2차원 표현이며, 여기서 x축은 시간을 나타내고 y축은 병렬 작업자 풀을 나타냅니다.작업자 수와 총 계산 시간은 더 작은 직사각형이 그려진 직사각형의 확장을 표시합니다.이 작은 직사각형은 원자 단위 작업(태스켈)을 나타냅니다.
아래에서 고밀도 시나리오에 대한 풀의 청크 크기 알고리즘의 DM 데이터로 그려진 PS의 시각화를 확인할 수 있습니다.
- x축은 동일한 시간 단위로 분할되며, 여기서 각 단위는 태스켈이 필요로 하는 계산 시간을 나타냅니다.
- y축은 풀에서 사용하는 작업자 프로세스 수로 나뉩니다.
- 여기서 작업 표시줄은 가장 작은 청록색 사각형으로 표시되며 익명 작업자 프로세스의 타임라인(스케줄)에 배치됩니다.
- 작업은 동일한 색상으로 연속적으로 강조 표시된 작업 시간대의 하나 이상의 태스켈입니다.
- 공회전 시간 단위는 빨간색 타일을 통해 표시됩니다.
- 병렬 예약은 섹션으로 분할됩니다.마지막 부분은 꼬리 부분입니다.
구성된 부품의 이름은 아래 그림에서 확인할 수 있습니다.
OM을 포함한 완전한 PM에서 공회전 점유율은 꼬리에 국한되지 않고 작업 간, 심지어 태스켈 간의 공간으로 구성됩니다.
6.3 효율성
위에 소개된 모델을 통해 작업자 활용률을 정량화할 수 있습니다.다음을 구별할 수 있습니다.
- 분포 효율성(DE) - DM(또는 조밀 시나리오의 단순화된 방법)의 도움을 받아 계산됩니다.
- 병렬화 효율성(PE) - 보정된 PM(예측)의 도움을 받아 계산되거나 실제 계산의 메타데이터에서 계산됩니다.
계산된 효율성이 주어진 병렬화 문제에 대한 전체 계산 속도와 자동으로 상관되지 않는다는 점에 유의해야 합니다.이러한 맥락에서 작업자 활용은 시작되었지만 완료되지 않은 작업자와 그러한 "개방된" 작업자가 없는 작업자를 구별할 뿐입니다.즉, 태스켈의 시간 범위 동안 공회전 가능성이 등록되지 않습니다.
위에서 언급한 모든 효율성은 기본적으로 분주한 공유/병렬 일정의 비율을 계산하여 얻을 수 있습니다.DE와 PE의 차이는 비지 공유가 오버헤드 확장 PM에 대한 전체 병렬 스케줄의 더 작은 부분을 차지하기 때문입니다.
이 답변에서는 밀도가 높은 시나리오에 대한 DE를 계산하는 간단한 방법에 대해서만 자세히 설명합니다.이것은 다른 청크 크기 알고리즘을 비교하기에 충분합니다. 왜냐하면...
- DM은 다른 청크 크기 알고리즘을 사용하면 변경되는 PM의 일부입니다.
- 태스켈당 계산 지속 시간이 동일한 고밀도 시나리오는 이러한 시간 범위가 방정식에서 제외되는 "안정적인 상태"를 나타냅니다.태스켈의 순서가 중요하기 때문에 다른 시나리오는 무작위 결과로 이어질 수 있습니다.
6.3.1 절대유통효율(ADE)
이러한 기본 효율성은 일반적으로 사용 중인 공유를 병렬 스케줄의 전체 잠재력으로 나누어 계산할 수 있습니다.
절대 분배 효율성(ADE) = 통화 중 공유 / 병렬
조밀 시나리오의 경우 단순화된 계산 코드는 다음과 같습니다.
# mp_utils.py
def calc_ade(n_workers, len_iterable, n_chunks, chunksize, last_chunk):
"""Calculate Absolute Distribution Efficiency (ADE).
`len_iterable` is not used, but contained to keep a consistent signature
with `calc_rde`.
"""
if n_workers == 1:
return 1
potential = (
((n_chunks // n_workers + (n_chunks % n_workers > 1)) * chunksize)
+ (n_chunks % n_workers == 1) * last_chunk
) * n_workers
n_full_chunks = n_chunks - (chunksize > last_chunk)
taskels_in_regular_chunks = n_full_chunks * chunksize
real = taskels_in_regular_chunks + (chunksize > last_chunk) * last_chunk
ade = real / potential
return ade
Idling Share가 없을 경우 Busy Share는 Parallel Schedule과 동일하므로 ADE는 100%입니다.단순화된 모델에서, 이것은 사용 가능한 모든 프로세스가 모든 작업을 처리하는 데 필요한 전체 시간 동안 사용되는 시나리오입니다.즉, 전체 작업이 효과적으로 100%로 병렬화됩니다.
그런데 왜 제가 여기서 PE를 절대 PE라고 계속 언급할까요?
이를 이해하려면 최대 스케줄링 유연성을 보장하는 청크 크기(cs)에 대한 가능한 사례를 고려해야 합니다(또한 하이랜더 수도 가능).우연?:
_______________________________________________________________________________________________________________________________.
예를 들어, 우리가 4개의 작업 공정과 37개의 태스켈을 가지고 있다면, 그것을 가지고도 유휴 작업자들이 있을 것입니다.chunksize=1 지단때에문▁just▁because지n_workers=437의 지수가 ./ 41.37 / 4 나는나 1다니입니다.나머지 3개는 공회전 중이고 나머지 1개는 단독 작업자가 처리해야 합니다.
마찬가지로, 39개의 태스켈을 가진 유휴 작업자가 여전히 있을 것입니다. 어떻게 하면 아래 사진을 볼 수 있을까요?
의 상위 병렬 예약을 비교할 때chunksize=1다음 버전과 함께chunksize=3상단 평행 일람표가 더 작고 x축의 타임라인이 더 짧다는 것을 알 수 있습니다.이제는 청크 크기가 예상치 못하게 커지면 고밀도 시나리오에서도 전체 계산 시간이 증가할 수 있다는 것이 분명합니다.
하지만 효율성 계산을 위해 x축의 길이를 사용하는 것은 어떨까요?
오버헤드가 이 모델에 포함되어 있지 않기 때문입니다.두 청크 크기 모두에서 다르므로 x축은 실제로 직접 비교할 수 없습니다.아래 그림에서 사례 2와 같이 오버헤드로 인해 총 계산 시간이 더 길어질 수 있습니다.
6.3.2 상대 분포 효율(RDE)
청크 크기가 1로 설정된 상태에서 태스켈을 더 잘 배포할 수 있는 경우 ADE 값에는 정보가 포함되지 않습니다.여기서 더 낫다는 것은 여전히 공회전 점유율이 더 작다는 것을 의미합니다.
가능한 최대 DE에 대해 DE 값을 조정하려면, 고려된 ADE를 우리가 얻는 ADE를 통해 분할해야 합니다.chunksize=1.
상대 분포 효율(RDE) = ADE_cs_x / ADE_cs_1
코드로 표시되는 방법은 다음과 같습니다.
# mp_utils.py
def calc_rde(n_workers, len_iterable, n_chunks, chunksize, last_chunk):
"""Calculate Relative Distribution Efficiency (RDE)."""
ade_cs1 = calc_ade(
n_workers, len_iterable, n_chunks=len_iterable,
chunksize=1, last_chunk=1
)
ade = calc_ade(n_workers, len_iterable, n_chunks, chunksize, last_chunk)
rde = ade / ade_cs1
return rde
RDE는 여기서 정의하는 바와 같이, 본질적으로 병렬 스케줄의 꼬리에 대한 이야기입니다.RDE는 테일에 포함된 최대 유효 청크 크기의 영향을 받습니다.(이 테일은 x축 길이일 수 있습니다.chunksize또는last_chunk.) 따라서 RDE는 아래 그림과 같이 모든 종류의 "테일 룩"에 대해 자연스럽게 100%(짝수)로 수렴됩니다.
낮은 RDE...
- 최적화 가능성에 대한 강력한 힌트입니다.
- 전체 병렬 예약의 상대적인 테일 부분이 줄어들기 때문에 더 긴 반복 가능성은 당연히 줄어듭니다.
여기에서 이 답변의 파트 II를 찾으십시오.
이 답변에 대하여
이 답변은 위에서 승인된 답변의 파트 II입니다.
순진함 vs.풀의 청크 크기-알고리즘
자세한 내용을 설명하기 전에 아래의 두 가지 GIF를 고려하십시오.한 의 경우iterable길이, 그들은 두 개의 비교된 알고리즘이 어떻게 통과된 것을 청크하는지 보여줍니다.iterable(그때까지 시퀀스가 될 것입니다) 및 결과 작업이 배포되는 방법.작업자의 순서는 무작위이며 실제로 작업자당 분산된 작업의 수는 와이드 시나리오의 라이트 태스켈 및/또는 태스켈에 대한 이 이미지와 다를 수 있습니다.앞서 언급했듯이 오버헤드도 여기에 포함되지 않습니다.하지만 전송된 데이터 크기가 무시되는 고밀도 시나리오에서 충분히 무거운 태스켈의 경우 실제 계산은 매우 유사한 그림을 그립니다.


5장에 표시된 바와 같이. 풀의 청크 크기-알고리즘"과 풀의 청크 크기-알고리즘을 사용하면 청크 수는 다음과 같이 안정됩니다.n_chunks == n_workers * 4해서 지적으로전동충안분큰히위반가해을능성복환는속하▁between▁for▁switching위해▁iter▁it▁enough,▁keeps▁while▁bigables을성능가반복큰.n_chunks == n_workers그리고.n_chunks == n_workers + 1이 적용됩니다.단순 알고리즘이 적용되는 경우:왜냐면n_chunks % n_workers == 1이라True위해서n_chunks == n_workers + 1단 한 명의 노동자만 고용되는 새로운 부서가 만들어질 것입니다.
Nive Chunksize-알고리즘:
동일한 수의 작업자로 태스크를 생성했다고 생각할 수 있지만, 이는 다음 기간 동안 남은 작업이 없는 경우에만 해당됩니다.
len_iterable / n_workers나머지가 있는 경우, 한 명의 작업자에 대해 하나의 작업만 수행하는 새로운 섹션이 있습니다.이 시점에서 계산은 더 이상 병렬되지 않습니다.
아래 그림은 5장에 표시된 것과 유사하지만 청크 수 대신 섹션 수를 표시하는 그림입니다. 청크 알고리즘에 (의전체청크알경의우즘풀리고기크경(우▁form풀의▁pool▁(gorith-als')n_pool2),n_sections악명 높은 하드 코딩된 요인에서 안정화될 것입니다.4순한알고의경우즘리진,,▁for경▁algorithm우▁the.n_sections1번과 2번 사이를 교대로 할 것입니다.
size-algorithm의 , 의 청 크 즘 경 는 화 안 우 정n_chunks = n_workers * 4앞서 언급한 추가 처리를 통해, 여기에 새로운 섹션이 생성되는 것을 방지하고 Idling Share를 충분히 오랫동안 반복할 수 있도록 한 작업자로 제한합니다.뿐만 아니라 알고리즘은 공회전 공유의 상대적 크기를 계속 축소하여 RDE 값이 100%로 수렴합니다.
" ough enough"는 " 분히오래는충는"래"를 의미합니다n_workers=4이라len_iterable=210예를들면.동일하거나 그 이상의 반복 가능한 경우, 공회전 점유율은 한 명의 근로자로 제한되며, 이는 원래 다음으로 인해 손실된 특성입니다.4-chunksize 내에서 곱셈을 수행합니다. -첫 번째로 계산합니다.
단순 청크 크기 알고리즘도 100%로 수렴하지만 속도가 너무 느립니다.수렴 효과는 두 개의 섹션이 있을 경우 꼬리의 상대적인 부분이 축소된다는 사실에 전적으로 의존합니다.인 이 길이로 됩니다.n_workers - 1 잔량여대의 .len_iterable / n_workers.
순진한 RDE와 풀의 청크 크기 알고리즘의 실제 RDE 값은 어떻게 다릅니까?
아래에는 2에서 100까지의 모든 작업자 수에 대해 최대 5000까지의 허용 가능한 길이에 대한 RDE 값을 보여주는 두 개의 열 지도가 있습니다.색상 척도는 0.5에서 1(50%-100%)입니다.왼쪽 열 지도에서 나이브 알고리즘의 어두운 영역(낮은 RDE 값)이 훨씬 더 많이 표시됩니다.반대로, 오른쪽 풀의 청크 크기 알고리즘은 훨씬 더 밝은 그림을 그립니다.
왼쪽 아래 어두운 모서리 대 오른쪽 위 밝은 모서리의 대각선 기울기는 "지속 가능한" 작업자 수에 대한 의존성을 다시 보여줍니다.
각 알고리즘으로 얼마나 나빠질 수 있습니까?
풀의 청크 크기 알고리즘을 사용하는 경우 RDE 값 81.25%는 위에서 지정한 작업자 범위 및 반복 가능한 길이에 대한 가장 낮은 값입니다.
단순한 청크 크기 알고리즘을 사용하면 상황이 훨씬 더 악화될 수 있습니다.여기서 가장 낮은 계산 RDE는 50.72%입니다.이 경우 계산 시간의 거의 절반 동안 작업자 한 명이 실행됩니다.자, 조심하세요, 자랑스러운 나이츠 랜딩의 주인님들.;)
리얼리티 체크
이전 장에서 우리는 처음부터 다중 처리를 골치 아픈 주제로 만드는 사소한 세부 사항에서 제거된 순수 수학적 분포 문제에 대한 단순화된 모델을 고려했습니다.분포 모델(DM)만으로도 실제로 관찰된 작업자 활용도를 설명하는 데 얼마나 기여할 수 있는지 더 잘 이해하기 위해, 이제 실제 계산에 의해 그려진 병렬 일정에 대해 살펴보겠습니다.
세우다
다음 그림은 모두 단순한 CPU 바인딩 더미 함수의 병렬 실행을 처리합니다. 이 함수는 다양한 인수를 사용하여 호출되므로 그려진 병렬 스케줄이 입력 값에 따라 어떻게 변화하는지 관찰할 수 있습니다.이 함수 내의 "작업"은 범위 개체에 대한 반복으로만 구성됩니다.우리가 엄청난 숫자를 전달하기 때문에 이것은 이미 코어를 계속 사용하기에 충분합니다.으로 이 의 추가 기능을 합니다.data변경되지 않은 채로 반환됩니다.모든 태스켈은 정확히 동일한 양의 작업으로 구성되어 있기 때문에, 우리는 여전히 고밀도 시나리오를 다루고 있습니다.
함수는 ns 해상도(파이썬 3.7+)로 타임스탬프를 찍는 래퍼로 장식됩니다.타임스탬프는 작업 표시줄의 시간 범위를 계산하여 경험적 병렬 일람표를 그릴 수 있도록 하는 데 사용됩니다.
@stamp_taskel
def busy_foo(i, it, data=None):
"""Dummy function for CPU-bound work."""
for _ in range(int(it)):
pass
return i, data
def stamp_taskel(func):
"""Decorator for taking timestamps on start and end of decorated
function execution.
"""
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time_ns()
result = func(*args, **kwargs)
end_time = time_ns()
return (current_process().name, (start_time, end_time)), result
return wrapper
풀의 스타맵 메서드도 스타맵 호출 자체만 시간이 지정되도록 구성됩니다.이 통화의 "시작"과 "종료"는 생성된 병렬 스케줄의 x축에서 최소 및 최대를 결정합니다.
우리는 다음과 같은 사양을 가진 기계에서 4개의 작업자 프로세스에 대한 40개의 태스켈의 계산을 관찰할 것입니다: Python 3.7.1, Ubuntu 18.04.2, Intel® Core™ i7-2600K CPU @ 3.40GHz x 8
변경되는 입력 값은 for-loop의 반복 횟수(30k, 30M, 600M)와 추가 전송 데이터 크기(태스텔당, numpy-nd 어레이: 0 MiB, 50 MiB)입니다.
...
N_WORKERS = 4
LEN_ITERABLE = 40
ITERATIONS = 30e3 # 30e6, 600e6
DATA_MiB = 0 # 50
iterable = [
# extra created data per taskel
(i, ITERATIONS, np.arange(int(DATA_MiB * 2**20 / 8))) # taskel args
for i in range(LEN_ITERABLE)
]
with Pool(N_WORKERS) as pool:
results = pool.starmap(busy_foo, iterable)
아래에 표시된 런은 배포 모델의 병렬 예약과 비교하여 차이를 더 잘 식별할 수 있도록 청크 순서가 동일하도록 직접 선택되었지만 작업자가 작업을 받는 순서는 결정적이지 않습니다.
DM 예측
다시 한 번 말씀드리지만, 분포 모델은 6.2장에서 이미 살펴본 것처럼 병렬 일정을 "예측"합니다.
1차 실행: 작업자당 30,000회 반복 및 0MiB 데이터
우리의 첫 운행은 매우 짧으며, 태스켈은 매우 가볍습니다. 체전.pool.starmap()-call은 총 14.5ms 밖에 걸리지 않았습니다.DM과 반대로 공회전은 꼬리 부분에만 국한되지 않고 작업과 태스커틀 사이에서도 발생합니다.그것은 우리의 실제 일정이 자연스럽게 모든 종류의 간접비를 포함하기 때문입니다.여기서 빈둥거리는 것은 태스켈 밖의 모든 것을 의미합니다.이미 언급한 바와 같이 태스켈 중에 실제 공회전이 발생할 수 있는 경우는 포착되지 않습니다.
또한, 모든 근로자가 동시에 업무를 수행하는 것은 아니라는 것을 알 수 있습니다.그것은 모든 근로자들이 공유되는 것에 대해 음식을 먹이기 때문입니다.inqueue한 번에 한 명의 직원만 읽을 수 있습니다.동일한 사항이 적용됩니다.outqueue이로 인해 한계가 아닌 크기의 데이터를 전송하는 즉시 더 큰 문제가 발생할 수 있습니다.
또한 모든 태스켈이 동일한 양의 작업을 구성하고 있음에도 불구하고 태스켈의 실제 측정 시간은 크게 다르다는 것을 알 수 있습니다.worker-3 및 worker-4에 배포된 태스켈은 처음 두 작업자가 처리한 태스켈보다 더 많은 시간이 필요합니다.이 실행의 경우 작업자-3/4의 코어에서 터보 부스트를 더 이상 사용할 수 없기 때문인 것으로 의심되므로 작업을 더 낮은 클럭 속도로 처리했습니다.
전체 계산이 너무 가벼워서 하드웨어나 OS가 도입한 혼돈 요소가 PS를 크게 왜곡할 수 있습니다.계산은 "바람 위의 나뭇잎"이며 DM-예측은 이론적으로 적합한 시나리오에서도 거의 의미가 없습니다.
2차 실행: 30M 반복 및 태스켈당 0MiB 데이터
for-loop의 반복 횟수를 30,000회에서 3,000만회로 늘리면 DM이 제공하는 데이터로 예측한 것과 완벽하게 일치하는 실제 병렬 스케줄이 생성됩니다. 만세!이제 태스켈당 계산은 시작과 그 사이의 공회전 부분을 주변화할 수 있을 정도로 무거워서 DM이 예측한 큰 공회전 점유율만 볼 수 있습니다.
3차 실행: 30M 반복 및 태스켈당 50MiB 데이터
30M 반복을 유지하면서 추가로 태스켈당 50MiB를 앞뒤로 보내면 그림이 다시 왜곡됩니다.여기서 대기열 효과를 잘 볼 수 있습니다.worker-4는 worker-1보다 두 번째 작업을 더 오래 기다려야 합니다.이제 70명의 노동자들이 있는 이 일정을 상상해 보세요!
태스켈이 계산적으로 매우 가벼우면서도 페이로드로 상당한 양의 데이터를 제공하는 경우, 단일 공유 대기열의 병목 현상으로 인해 물리적 코어에 의해 지원되는 작업자 수가 증가하더라도 풀에 더 많은 작업자가 추가되는 이점을 방지할 수 있습니다.이러한 경우 Worker-1은 첫 번째 작업을 완료하고 Worker-40이 첫 번째 작업을 시작하기도 전에 새 작업을 대기할 수 있습니다.
제이 에서 계산 이 필요한지는 해 질 입니다.Pool작업자 수에 따라 항상 선형적으로 감소하지 마십시오.상대적으로 많은 양의 데이터를 전송하면 대부분의 시간이 작업자의 주소 공간에 데이터가 복사되기를 기다리는 데 소요되고 한 번에 한 작업자만 공급될 수 있는 시나리오가 발생할 수 있습니다.
4차 실행: 600M 반복 및 태스켈당 50MiB 데이터
여기서 우리는 50 MiB를 다시 보내지만 반복 횟수를 30M에서 600M으로 늘려 총 계산 시간을 10초에서 152초로 늘립니다.다시 작성된 병렬 스케줄은 예측된 스케줄과 완벽하게 일치하며, 데이터 복사를 통한 오버헤드가 최소화됩니다.
결론
은 의된곱기에 의한 입니다.4스케줄링 유연성을 높이는 동시에 태스켈 분포의 불균일성도 활용합니다.이 곱셈이 없으면 공회전 공유는 짧은 반복 가능한 경우에도 단일 작업자로 제한됩니다(고밀도 시나리오 DM의 경우). 풀의 청크 크기 알고리즘은 해당 특성을 되찾기 위해 특정 크기의 입력 반복 가능한 크기여야 합니다.
이 대답이 보여주었듯이, 풀의 청크 크기 알고리듬은 적어도 평균적인 경우와 오버헤드를 고려하지 않는 한 순진한 접근 방식에 비해 평균적으로 더 나은 코어 활용률을 이끌어냅니다.여기서 단순한 알고리즘은 ~51%까지 낮은 분포 효율성(DE)을 가질 수 있는 반면, 풀의 청크 크기 알고리즘은 ~81%로 낮습니다.그러나 DE는 IPC처럼 병렬화 오버헤드(PO)를 포함하지 않습니다.제8장은 DE가 여전히 간접비를 최소화한 고밀도 시나리오에 대해 큰 예측력을 가질 수 있다는 것을 보여주었습니다.
풀의 청크 크기 알고리듬은 순진한 접근 방식에 비해 더 높은 DE를 달성하지만, 모든 입력 구성에 대해 최적의 태스켈 분포를 제공하지는 않습니다.단순한 정적 청킹 알고리즘이 PE(오버헤드 포함)를 최적화할 수는 없지만, 항상 100%의 상대적 분산 효율(RDE)을 제공할 수 없는 본질적인 이유는 없습니다. 즉, 다음과 같은 DE를 제공할 수 없습니다.chunksize=1간단한 청크 크기 알고리즘은 기본적인 수학으로만 구성되며 어떤 식으로든 "케이크를 조각"할 수 있습니다.
풀의 "동일한 크기의 청킹" 알고리즘 구현과 달리, "짝수 크기의 청킹" 알고리즘은 모든 데이터에 대해 100%의 RDE를 제공합니다.len_iterable/n_workers짝수 Pool의하는 것이 더 할 수 , 만으로 기존 할 수 짝수 크기 청킹 알고리즘은 Pool의 소스에서 구현하는 것이 약간 더 복잡할 수 있지만, 작업을 외부로 패키징하는 것만으로 기존 알고리즘 위에서 변조할 수 있습니다(그 방법에 대한 Q/A를 떨어뜨릴 경우를 대비하여 여기에서 링크하겠습니다).
제 생각에 당신이 놓치고 있는 부분은 당신의 순진한 추정치가 각 작업 단위에 동일한 시간이 소요된다고 가정한다는 것입니다. 이 경우 당신의 전략이 최선일 것입니다.그러나 일부 작업이 다른 작업보다 빨리 완료되면 느린 작업이 완료될 때까지 기다리는 동안 일부 코어가 유휴 상태가 될 수 있습니다.
따라서 청크를 4배 더 많은 조각으로 분할하여 한 청크가 일찍 완료되면 해당 코어가 다음 청크를 시작할 수 있습니다(다른 코어는 느린 청크에서 계속 작업함).
나는 그들이 정확하게 4번 요소를 선택한 이유를 모르지만, 그것은 지도 코드의 오버헤드를 최소화하는 것(가능한 가장 큰 청크를 원하는 것)과 다른 시간(가능한 가장 작은 청크를 원하는 것)이 걸리는 균형 청크 사이의 절충이 될 것입니다.
언급URL : https://stackoverflow.com/questions/53751050/multiprocessing-understanding-logic-behind-chunksize
'programing' 카테고리의 다른 글
| 이 이상한 행동을 C#으로 서명된 플로트로 설명할 수 있는 사람이 있습니까? (0) | 2023.05.02 |
|---|---|
| PowerShell에서 출력을 무시하는 더 나은(깨끗한) 방법은 무엇입니까? (0) | 2023.05.02 |
| 내 보기(aspx 페이지)에서 모델 상태에 액세스하려면 어떻게 해야 합니까? (0) | 2023.05.02 |
| 워크북 닫기 시 Excel VBA에서 클립보드 프롬프트 사용 안 함 (0) | 2023.05.02 |
| pathlib의 절대 경로를 얻는 방법.경로 객체? (0) | 2023.05.02 |



















