concurrent 또는 parallel
일을 겹치는 두 가지 방법입니다. 이름만 다른 같은 연산자가 아닙니다.
FxAsync<T> FxAsync.concurrent(int length)
FxAsync<R> Fx.parallel(int workers, FutureOr<R> Function(T input) worker)
FxAsync<R> Fx.mapConcurrent(int concurrency, FutureOr<R> Function(T a) f)
FxAsync<R> Fx.mapParallel(int workers, FutureOr<R> Function(T input) worker)
강의
concurrent(n)은
Future를 이 isolate 위에서 겹칩니다 — I/O, 기다림.
parallel(n, worker)은
CPU 일을 다른 isolate들에 겹칩니다. 콜백이 시간을 어디에
쓰는지로 고르세요. "더 빠르게" 하고 싶은 양이 아닙니다.
concurrent(n) | parallel(n) | |
|---|---|---|
| 겹치는 것 | 이 isolate의 Future | 워커 isolate |
| 콜백 | 아무 클로저 | top-level 또는 static 함수 |
| 값 | 무엇이든 | 보낼 수 있는 것 |
| 플랫폼 | VM, Flutter, web | VM / Flutter만 |
싼 일 (x + 1, Future.delayed(0)) | 마커뿐, hop이 싸다 | 원소마다 isolate 메시지 — 대개 손해 |
| 맞는 일 | HTTP, DB, 파일, await | JSON 파싱, 이미지, 암호화, tight loop |
I/O는 대부분 기다림입니다. 요청이 떠 있는 동안 isolate는 쉬고
있으므로 concurrent(4)로 Future 네 개를
겹치면 벽시계가 줄고, 다른 isolate는 필요 없습니다. CPU 일이
곧 isolate입니다. 반환할 때까지 이벤트 루프(그리고 Flutter
프레임)를 막습니다. 그때 쓰는 것이 parallel입니다.
isolate hop은 공짜가 아닙니다. 각 원소를 직렬화하고, 보내고, 돌리고,
다시 직렬화하고, 순서를 맞춥니다. 본문이 x + 1인
콜백은 덧셈보다 hop에 더 오래 걸립니다. 워커를 네 개로 늘리면
더 느려집니다. 거둘 CPU는 없는데 택배비는 네 배입니다.
측정: x + 1 천 개는 워커 네 개가 하나보다 약 두 배
걸렸고, 20000번 tight loop는 워커 네 개가 하나보다 약 두 배
빨랐습니다. 일이 hop보다 무겁지 않으면 이 isolate에
남으세요.
// I/O — overlap Futures here
fx(ids).mapConcurrent(8, fetchUser);
// CPU — only when the body is heavy enough
fx(blobs).parallel(parallelWorkers, parseJson);
// This is a loss. The hop is bigger than the work.
fx(nums).parallel(4, (x) => x + 1);
관련:
concurrent — I/O, 아무 클로저 ·
mapConcurrent — 결합된 I/O 형태 ·
parallel — CPU, 보낼 수 있는 워커 ·
mapParallel — parallel의 별칭