Share via


일정 예약 개요

Orleans에는 조직과 두 가지 형태의 일정 예약이 있습니다.

  1. 요청 예약, 요청 예약에 설명된 일정 규칙에 따라 실행을 위해 들어오는 조직 호출의 예약입니다.
  2. 작업 예약: 단일 스레드 방식으로 실행할 코드의 동기 블록 예약

모든 조직 코드는 조직의 작업 스케줄러에서 실행됩니다. 즉, 요청도 조직의 작업 스케줄러에서 실행됩니다. 요청 예약 규칙에서 여러 요청을 동시에 실행할 수 있더라도, 조직의 작업 스케줄러는 항상 작업을 하나씩 실행하여 병렬로 여러 작업을 실행하지 않으므로 요청이 병렬로 실행되지 않습니다.

작업 예약

일정 예약을 더 잘 이해하려면 메시지를 로그하고 잠시 기다렸다가 다른 메시지를 로그한 후 반환하는 DelayExecution()이라는 메서드가 있는 다음 MyGrain 조직을 고려합니다.

public interface IMyGrain : IGrain
{
    Task DelayExecution();
}

public class MyGrain : Grain, IMyGrain
{
    private readonly ILogger<MyGrain> _logger;

    public MyGrain(ILogger<MyGrain> logger) => _logger = logger;

    public async Task DelayExecution()
    {
        _logger.LogInformation("Executing first task");

        await Task.Delay(1_000);

        _logger.LogInformation("Executing second task");
    }
}

이 메서드를 실행하면 메서드 본문이 다음 두 부분으로 실행됩니다.

  1. 첫 번째 _logger.LogInformation(...) 호출과 Task.Delay(1_000) 호출
  2. 두 번째 _logger.LogInformation(...) 호출

두 번째 작업은 Task.Delay(1_000) 호출이 완료될 때까지 조직의 작업 스케줄러에서 예약되지 않으며, 이 시점에서 조직 메서드의 연속을 예약합니다.

다음은 요청을 예약하고 두 작업으로 실행하는 방법을 그래픽으로 표현한 것입니다.

Two-Task-based request execution example.

위의 설명은 Orleans에 국한되지 않으며 .NET에서 작업 일정 예약이 작동하는 방식입니다. C#의 비동기 메서드는 컴파일러에 의해 비동기 상태 컴퓨터로 변환되고 실행은 별개의 단계로 비동기 상태 컴퓨터를 통해 진행됩니다. 각 단계는 현재 TaskScheduler(TaskScheduler.Current를 통해 액세스, 기본값은 TaskScheduler.Default) 또는 현재 SynchronizationContext에서 예약됩니다. TaskScheduler를 사용하는 경우 메서드의 각 단계는 해당 TaskScheduler에 전달되는 Task 인스턴스로 표시됩니다. 따라서 .NET에서 Task는 두 가지 개념적 항목을 나타낼 수 있습니다.

  1. 대기할 수 있는 비동기 작업입니다. 위의 DelayExecution() 메서드 실행은 대기할 수 있는 Task로 표시됩니다.
  2. 동기 작업 블록에서 위의 DelayExecution() 메서드 내에 있는 각 단계는 Task로 표시됩니다.

TaskScheduler.Default를 사용 중인 경우 연속 작업은 .NET ThreadPool에 직접 예약되며 Task 개체에 래핑되지 않습니다. Task 인스턴스에서 연속 작업의 래핑은 투명하게 수행되므로 개발자는 이러한 구현 세부 정보를 알 필요가 거의 없습니다.

Orleans에서 작업 예약

각 조직 활성화에는 조직의 단일 스레드 실행 모델을 적용하는 자체 TaskScheduler 인스턴스가 있습니다. 내부적으로 이 TaskSchedulerActivationTaskSchedulerWorkItemGroup을 통해 구현됩니다. WorkItemGroup은 작업을 Queue<T>의 큐에 넣어 유지하고 여기서 T는 내부적으로 Task이며 IThreadPoolWorkItem을 구현합니다. 현재 큐에 넣은 각 Task를 실행하기 위해 WorkItemGroup은 .NET ThreadPool에서 자체적으로 예약합니다. .NET ThreadPool에서 WorkItemGroupIThreadPoolWorkItem.Execute() 메서드를 호출하면 WorkItemGroup은 큐에 넣은 Task 인스턴스를 하나씩 실행합니다.

각 조직에는 .NET ThreadPool에서 자체적으로 예약하여 실행하는 스케줄러가 있습니다.

Orleans grains scheduling themselves on the .NET ThreadPool.

각 스케줄러에는 작업 큐가 포함됩니다.

Scheduler queue of scheduled tasks.

.NET ThreadPool은 큐에 넣은 각 작업 항목을 실행합니다. 여기에는 Task.Run(...)을 통해 예약된 작업 항목과 같은 다른 작업 항목뿐만 아니라 조직 스케줄러도 포함됩니다.

Visualization of the all schedulers running in the .NET ThreadPool.

참고 항목

조직의 스케줄러는 한 번에 하나의 스레드에서만 실행할 수 있지만 항상 동일한 스레드에서 실행되는 것은 아닙니다. .NET ThreadPool은 조직의 스케줄러가 실행될 때마다 다른 스레드를 자유롭게 사용할 수 있습니다. 조직의 스케줄러는 한 번에 하나의 스레드에서만 실행되도록 하는 역할을 하며, 이것이 조직의 단일 스레드 실행 모델이 구현되는 방식입니다.