排程概觀
Orleans 中有兩種排程形式與粒紋相關:
- 要求排程,根據 [要求排程] 中所討論的排程規則,對執行的傳入粒紋呼叫進行排程。
- 工作排程,要以單一執行緒方式執行之程式碼同步區塊的排程
所有粒紋程式碼都會在粒紋的工作排程器上執行,這表示要求也會在粒紋的工作排程器上執行。 即使要求排程的規則允許多個要求「同時」執行,這些要求也不會「平行」執行,因為粒紋的工作排程器一律會逐一執行工作,因此永遠不會平行執行多個工作。
作業排程
若要進一步了解排程,請考慮下列粒紋 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");
}
}
執行這個方法時,方法主體會以兩個部分執行:
- 第一個
_logger.LogInformation(...)
呼叫和對於Task.Delay(1_000)
的呼叫。 - 第二個
_logger.LogInformation(...)
呼叫。
第二個工作將不會排程在粒紋的工作排程器上,直到 Task.Delay(1_000)
呼叫完成為止,此時它會排程粒紋方法的「接續」。
以下是如何作為兩個工作排程及執行要求的圖形標記法:
上述描述並非專用於 Orleans,而是工作排程在 .NET 中的運作方式: C# 中的非同步方法會由編譯器轉換成非同步狀態機器,並在離散步驟中透過非同步狀態機器執行。 每個步驟都會在目前的 TaskScheduler (透過 TaskScheduler.Current 存取,預設為 TaskScheduler.Default) 或目前的 SynchronizationContext 上排程。 如果使用 TaskScheduler
,則方法中的每個步驟都會以傳遞給該 TaskScheduler
的 Task
執行個體來表示。 因此,.NET 中的 Task
可以代表兩個概念性事項:
- 可以等候的非同步作業。 上述
DelayExecution()
方法的執行是由可以等候的Task
來表示。 - 在同步的工作區塊中,上述
DelayExecution()
方法中的每個階段都會以Task
表示。
當 TaskScheduler.Default
為使用中時,接續會直接排程至 .NET ThreadPool,而不會包裝在 Task
物件中。 Task
執行個體中的接續包裝會以透明方式發生,因此開發人員很少需要注意這些實作詳細資料。
Orleans 中的工作排程
每個粒紋啟用都有自己的 TaskScheduler
執行個體,負責強制執行粒紋的「單一執行緒」執行模型。 在內部,這個 TaskScheduler
會透過 ActivationTaskScheduler
和 WorkItemGroup
實作。 WorkItemGroup
會在 Queue<T> 中保留排入佇列的工作,其中 T
是內部的 Task
且會實作 IThreadPoolWorkItem。 若要執行每個目前排入佇列的 Task
,WorkItemGroup
會在 .NET ThreadPool
上排程其「本身」。 當 .NET ThreadPool
叫用 WorkItemGroup
的 IThreadPoolWorkItem.Execute()
方法時,WorkItemGroup
會逐一執行排入佇列的 Task
執行個體。
每個粒紋都有一個排程器,其會藉由在 .NET ThreadPool
上排程其本身來執行:
每個排程器都包含一個工作佇列:
.NET ThreadPool
會執行排入佇列的每個工作項目。 這包括粒紋排程器和其他工作項目,例如透過 Task.Run(...)
排程的工作項目:
注意
粒紋的排程器一次只能在一個執行緒上執行,但不一定會在同一個執行緒上執行。 每次執行粒紋排程器時,.NET ThreadPool
都可以使用不同的執行緒。 粒紋的排程器負責確保其一次只會在一個執行緒上執行,這是實作粒紋的單一執行緒執行模型的方法。