본문 바로가기

동시성

업데이트됨

번역일: 2026년 6월 20일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 6월 20일
번역 갱신
2026년 6월 20일

동시성

소개

서로 의존하지 않는 여러 개의 느린 작업을 실행해야 할 때, 이를 순차적으로 처리하는 대신 동시에 실행하면 성능을 크게 향상시킬 수 있습니다. Laravel의 Concurrency 파사드는 클로저를 동시에 실행할 수 있는 간단하고 편리한 API를 제공합니다.

동작 원리

Laravel은 전달된 클로저를 직렬화(serialize)한 뒤, 숨겨진 Artisan CLI 명령으로 디스패치합니다. 해당 명령은 각각 독립된 PHP 프로세스 내에서 클로저를 역직렬화(unserialize)하고 실행합니다. 클로저 실행이 끝나면 반환값을 다시 직렬화하여 부모 프로세스로 전달합니다.

Concurrency 파사드는 세 가지 드라이버를 지원합니다: process(기본값), fork, sync.

fork 드라이버는 기본 process 드라이버보다 성능이 뛰어나지만, PHP는 웹 요청 중 포킹(forking)을 지원하지 않으므로 CLI 환경에서만 사용할 수 있습니다. 사용하려면 spatie/fork 패키지를 먼저 설치해야 합니다.

composer require spatie/fork

sync 드라이버는 주로 테스트 환경에서 유용합니다. 동시성을 비활성화하고 부모 프로세스 내에서 클로저를 순차적으로 실행하기 때문에, 동시 실행 없이 로직만 검증하고 싶을 때 사용합니다.

동시 작업 실행

동시 작업을 실행하려면 Concurrency 파사드의 run 메서드를 호출합니다. run 메서드는 클로저 배열을 받아 각 클로저를 자식 PHP 프로세스에서 동시에 실행합니다.

use Illuminate\Support\Facades\Concurrency; use Illuminate\Support\Facades\DB; [$userCount, $orderCount] = Concurrency::run([ fn () => DB::table('users')->count(), fn () => DB::table('orders')->count(), ]);

특정 드라이버를 사용하려면 driver 메서드를 호출하면 됩니다.

$results = Concurrency::driver('fork')->run(...);

기본 동시성 드라이버를 변경하고 싶다면, config:publish Artisan 명령으로 concurrency 설정 파일을 퍼블리시한 뒤, 해당 파일의 default 옵션을 수정하세요.

php artisan config:publish concurrency

이름 있는 결과

결과를 순서(인덱스)가 아닌 이름으로 접근하고 싶다면, 연관 배열(associative array) 형태로 클로저를 전달하면 됩니다. 각 결과는 해당 클로저의 키 이름으로 반환됩니다.

use Illuminate\Support\Facades\Concurrency; use Illuminate\Support\Facades\DB; $results = Concurrency::run([ 'users' => fn () => DB::table('users')->count(), 'orders' => fn () => DB::table('orders')->count(), ]); $userCount = $results['users']; $orderCount = $results['orders'];

인덱스 기반 접근은 클로저 순서가 바뀌면 버그로 이어질 수 있으므로, 결과를 여러 곳에서 참조할 때는 이름 있는 결과 방식을 사용하는 것이 좋습니다.

작업 타임아웃

process 드라이버(기본값)를 사용할 때는 run 메서드에 timeout 옵션을 지정하여 각 동시 작업이 실행될 수 있는 최대 시간(초)을 설정할 수 있습니다. 지정한 시간 내에 완료되지 않으면 해당 작업은 강제 종료됩니다.

use Illuminate\Support\Facades\Concurrency; use Illuminate\Support\Facades\DB; [$userCount, $orderCount] = Concurrency::run([ fn () => DB::table('users')->count(), fn () => DB::table('orders')->count(), ], timeout: 30);

더 표현력 있는 방식을 선호한다면 CarbonInterval 인스턴스를 전달할 수도 있습니다.

use Illuminate\Support\Facades\Concurrency; use function Illuminate\Support\seconds; Concurrency::run([...], timeout: seconds(30));

NOTE

타임아웃은 process 드라이버에서만 지원됩니다. fork 드라이버 사용 시에는 이 옵션이 적용되지 않습니다.

동시 작업 지연 실행

클로저를 동시에 실행하되, 그 반환값은 필요하지 않을 때는 defer 메서드를 사용하세요. defer를 호출하면 클로저가 즉시 실행되지 않고, HTTP 응답이 사용자에게 전송된 이후에 동시에 실행됩니다. 덕분에 응답 속도에 영향을 주지 않고 부가적인 작업을 처리할 수 있습니다.

use App\Services\Metrics; use Illuminate\Support\Facades\Concurrency; Concurrency::defer([ fn () => Metrics::report('users'), fn () => Metrics::report('orders'), ]);

예를 들어, 사용자의 요청을 처리한 뒤 지표 수집이나 로그 전송처럼 응답에 영향을 주지 않아도 되는 작업을 defer로 처리하면 사용자 체감 응답 속도를 개선할 수 있습니다.

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 20일