Gambaran umum penjadwalan
Ada dua bentuk penjadwalan Orleans yang relevan dengan biji-bijian:
- Minta penjadwalan, penjadwalan panggilan grain masuk untuk eksekusi sesuai dengan aturan penjadwalan yang dibahas dalam Penjadwalan permintaan.
- Penjadwalan tugas, penjadwalan blok kode sinkron yang akan dijalankan dengan cara satu utas
Semua kode biji-bijian dijalankan pada penjadwal tugas grain, yang berarti bahwa permintaan juga dijalankan pada penjadwal tugas grain. Bahkan jika aturan penjadwalan permintaan memungkinkan beberapa permintaan untuk dijalankan secara bersamaan, mereka tidak akan menjalankan secara paralel karena penjadwal tugas grain selalu menjalankan tugas satu per satu dan karenanya tidak pernah menjalankan beberapa tugas secara paralel.
Penjadwalan tugas
Untuk lebih memahami penjadwalan, pertimbangkan butir berikut, MyGrain
, yang memiliki metode yang memanggil DelayExecution()
log pesan, menunggu beberapa waktu, lalu mencatat pesan lain sebelum kembali.
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");
}
}
Ketika metode ini dijalankan, isi metode akan dijalankan dalam dua bagian:
- Panggilan pertama
_logger.LogInformation(...)
dan panggilan keTask.Delay(1_000)
. - Panggilan kedua
_logger.LogInformation(...)
.
Tugas kedua tidak akan dijadwalkan pada penjadwal tugas grain sampai Task.Delay(1_000)
panggilan selesai, di mana ia akan menjadwalkan kelanjutan metode biji-bijian.
Berikut adalah representasi grafis tentang bagaimana permintaan dijadwalkan dan dijalankan sebagai dua tugas:
Deskripsi di atas tidak spesifik untuk Orleans dan adalah bagaimana penjadwalan tugas dalam .NET bekerja: metode asinkron di C# dikonversi menjadi mesin status asinkron oleh kompilator dan eksekusi berlangsung melalui komputer status asinkron dalam langkah-langkah diskrit. Setiap langkah dijadwalkan pada saat ini TaskScheduler (diakses melalui TaskScheduler.Current, default ke TaskScheduler.Default) atau saat ini SynchronizationContext. TaskScheduler
Jika sedang digunakan, setiap langkah dalam metode diwakili oleh Task
instans yang diteruskan ke TaskScheduler
. Oleh karena itu, Task
dalam .NET dapat mewakili dua hal konseptual:
- Operasi asinkron yang dapat ditunggu. Eksekusi metode di
DelayExecution()
atas diwakili olehTask
yang dapat ditunggu. - Dalam blok pekerjaan yang sinkron, setiap tahap dalam metode di
DelayExecution()
atas diwakili olehTask
.
Ketika TaskScheduler.Default
sedang digunakan, kelanjutan dijadwalkan langsung ke .NET ThreadPool dan tidak dibungkus dalam Task
objek. Pembungkusan kelanjutan dalam Task
instans terjadi secara transparan dan oleh karena itu pengembang jarang perlu mengetahui detail implementasi ini.
Penjadwalan tugas di Orleans
Setiap aktivasi biji-bijian memiliki instans sendiri TaskScheduler
yang bertanggung jawab untuk memberlakukan model eksekusi satu utas biji-bijian. Secara internal, ini TaskScheduler
diimplementasikan melalui ActivationTaskScheduler
dan WorkItemGroup
. WorkItemGroup
menyimpan tugas antrean di Queue<T> tempat T
adalah Task
secara internal dan mengimplementasikan IThreadPoolWorkItem. Untuk menjalankan masing-masing yang saat ini diantrekan Task
, WorkItemGroup
jadwalkan sendiri pada .NET ThreadPool
. Ketika .NET ThreadPool
memanggil WorkItemGroup
metode 's IThreadPoolWorkItem.Execute()
, WorkItemGroup
menjalankan instans antrean Task
satu per satu.
Setiap butir memiliki penjadwal yang dijalankan dengan menjadwalkan dirinya sendiri pada .NET ThreadPool
:
Setiap penjadwal berisi antrean tugas:
.NET ThreadPool
menjalankan setiap item kerja yang diantrekan. Ini termasuk penjadwal biji-bijian serta item kerja lainnya, seperti item kerja yang dijadwalkan melalui Task.Run(...)
:
Catatan
Penjadwal grain hanya dapat dijalankan pada satu utas pada satu waktu, tetapi tidak selalu dijalankan pada utas yang sama. .NET ThreadPool
bebas menggunakan utas yang berbeda setiap kali penjadwal grain dijalankan. Penjadwal grain bertanggung jawab untuk memastikan bahwa itu hanya dijalankan pada satu utas pada satu waktu dan ini adalah bagaimana model eksekusi satu utas biji-bijian diimplementasikan.