共用方式為


排程概觀

在Orleans中,兩種排程形式與顆粒相關:

  1. 請求排程:根據 請求排程中所討論的規則,排定傳入的穀物請求以執行。
  2. 工作排程:以 單個線程 方式排程要執行的同步程式代碼區塊。

所有粒紋程式代碼都會在粒紋的工作排程器上執行,這表示要求也會在粒紋的工作排程器上執行。 即使要求排程規則允許多個要求同時執行,它們也不會平行執行,因為Grain的工作排程器一律會逐一執行工作,而且永遠不會平行執行多個工作。

工作排程

若要進一步瞭解排程,請考慮下列細節 MyGrain。 它有一個稱為 DelayExecution() 的方法,會記錄訊息、等候一段時間,然後在傳回之前記錄另一則訊息。

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)呼叫完成之前,第二個工作不會在Grain的工作排程器上排程。 此時,它會排程粒紋方法的 接續

以下是如何排程並執行要求作為兩個工作的圖形表示法:

雙任務型要求執行範例。

上述描述並非專屬於 Orleans;它描述工作排程在 .NET 中的運作方式。 C# 編譯器會將異步方法轉換成異步狀態機,並以離散的步驟運行此狀態機。 每個步驟都會在目前的TaskScheduler上排程(透過TaskScheduler.Current存取,預設為TaskScheduler.Default)或在目前的SynchronizationContext上。 如果使用TaskScheduler,方法中的每個步驟都會成為傳遞給該TaskTaskScheduler實例。 因此,在 .NET 中,Task 可以代表兩個概念:

  1. 可以等候的異步操作。 上述方法的執行 DelayExecution() 是由一個可以等候的 Task 表示物來表示。
  2. 同步工作區段。 上述方法中的每個 DelayExecution() 階段都會以 Task表示。

使用 TaskScheduler.Default 時,繼續會直接排程到 .NET ThreadPool,而且不會包裝在 Task 物件中。 在 Task 實例中的延續包裝會以透明方式發生,因此開發人員很少需要注意這些實作細節。

中的工作排程 Orleans

每個 grain 啟用都有自己的 TaskScheduler 實例,負責強制執行 grain 的 單線程 執行模型。 在內部,這個TaskScheduler是通過ActivationTaskSchedulerWorkItemGroup實作。 WorkItemGroup 會將佇列中的工作保留在 Queue<T> 裡,其中 T 作為內部的 Task,並實作 IThreadPoolWorkItem。 若要執行每個目前佇列中的TaskWorkItemGroup會在 .NET 上排程ThreadPool。 當 .NET ThreadPool 呼叫 WorkItemGroupIThreadPoolWorkItem.Execute() 方法時,WorkItemGroup 會逐一執行加入佇列的 Task 實例。

每個粒紋都有一個排程器,可藉由在 .NET ThreadPool上排程本身來執行:

Orleans 資料物件在 .NET ThreadPool 上自行排程。

每個排程器都包含一個工作佇列:

已排程工作的排程器佇列。

.NET ThreadPool 會執行每個佇列中的工作項目。 這包括 顆粒調度器以及透過Task.Run(...) 排程的其他工作項目:

.NET ThreadPool 中執行的所有排程器視覺效果。

備註

Grain 的排程器一次只能在一個執行緒上執行,但它不一定會在相同的執行緒上運行。 每次執行粒紋排程器時,.NET ThreadPool 可以自由使用不同的線程。 粒紋的排程器可確保它一次只在一個線程上執行,並實作粒紋的單 一線程 執行模型。