Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Tasarım gereği, grain kodundan oluşturulan tüm alt görevler (örneğin, await
, ContinueWith
veya Task.Factory.StartNew
kullanılarak) üst görevle aynı TaskScheduler başına etkinleştirmede dağıtılır. Bu nedenle, taneli kodun geri kalanıyla aynı tek iş parçacıklı yürütme modelini devralır. Bu, tek iş parçacıklı grenli dönüş tabanlı eşzamanlılık yürütmesinin arkasındaki ana noktadır.
Bazı durumlarda, belirli kodlar Orleans görev zamanlama modelinden "ayrılmalı" ve "özel bir şey yapmalı," örneğin Task
üzerinde farklı bir görev zamanlayıcısına veya .NET ThreadPool'ye açıkça işaret edebilir. Örnek olarak, zaman uyumlu bir uzaktan engelleme çağrısı (uzak G/Ç gibi) yürütmesi gereken tanecik kodu gösteriliyor. Bu engelleme çağrısının tanecik bağlamında yürütülmesi, taneciği engeller ve bu nedenle hiçbir zaman yapılmamalıdır. Bunun yerine, grain kodu bu engelleme kodu parçasını bir iş parçacığı havuzunda yürütebilir, bu yürütmenin tamamlanmasına katılabilir (await
) ve ardından grain bağlamında ilerleyebilir. Zamanlayıcıdan Orleans kaçışın, tipik kullanım modellerinin ötesinde çok gelişmiş ve nadiren gerekli bir kullanım senaryosu olması beklenir.
Görev tabanlı API'ler
await
, TaskFactory.StartNew (aşağıya bakın), Task.ContinueWith, Task.WhenAny, Task.WhenAllve Task.Delay tümü geçerli görev zamanlayıcıya saygı gösterir. Bunları farklı bir TaskScheduler belirtmeden, varsayılan şekilde kullanmak, onların tanecik bağlamında çalışmasına neden olur.Hem hem de Task.Run temsilcisi
endMethod
geçerli görev zamanlayıcısını dikkate almazTaskFactory.FromAsync. Her ikisi de .NET iş parçacığı havuzu görev zamanlayıcısını kullanırTaskScheduler.Default
. Bu nedenle,Task.Run
veendMethod
içindeki kod,Task.Factory.FromAsync
her zaman .NET iş parçacığı havuzunda, tanecikler için Orleans tek iş parçacıklı yürütme modelinin dışında çalışır. Ancak,await Task.Run
veyaawait Task.Factory.FromAsync
sonrası tüm kodlar, görevin oluşturulduğu noktada etkin olan zamanlayıcı altında çalışır ve bu zamanlayıcı, görevin zamanlayıcısıdır.Task.ConfigureAwait ile
false
, geçerli görev zamanlayıcısından kaçmak için açık bir API'dir.Task
'ın ardından kodun TaskScheduler.Default zamanlayıcısında (.NET iş parçacığı havuzu) yürütülmesine neden olur ve böylece taneciğin tek iş parçacıklı yürütülmesini bozar.Dikkat
Genel olarak tahıl kodunda
ConfigureAwait(false)
doğrudan hiçbir zaman kullanmayın.İmzalı
async void
yöntemler taneciklerle kullanılmamalıdır. Bunlar grafik kullanıcı arabirimi olay işleyicileri için tasarlanmıştır. Birasync void
yöntem, bir özel durumun kaçmasına izin verirse geçerli işlemi hemen kilitleyebilir ve özel durumu işlemenin hiçbir yolu yoktur. Bu, zaman uyumsuz bir temsilciList<T>.ForEach(async element => ...)
temsilcisine dönüştüğünden, Action<T> ve birasync void
kabul eden diğer yöntemler için de geçerlidir.
Task.Factory.StartNew
ve async
temsilciler
C# dilinde görevleri zamanlamak için genellikle Task.Run
yerine Task.Factory.StartNew
kullanılması önerilir.
Task.Factory.StartNew
için hızlı bir web araması tehlikeli olduğunu ve Task.Run
'nin her zaman tercih edilmesi önerilir. Ancak, tahılın tek iş parçacıklı yürütme modeli içinde kalmak için Task.Factory.StartNew
kullanılmalıdır. Peki, doğru şekilde nasıl kullanılır?
Task.Factory.StartNew()
'nin tehlikesi, zaman uyumsuz temsilciler için yerel destek olmamasıdır. Bu, gibi var notIntendedTask = Task.Factory.StartNew(SomeDelegateAsync)
kodun büyük olasılıkla bir hata olduğu anlamına gelir.
notIntendedTask
, sona erdiğinde tamamlanan bir SomeDelegateAsync
. Bunun yerine, döndürülen görevi her zaman açın: var task = Task.Factory.StartNew(SomeDelegateAsync).Unwrap()
.
Örnek: Birden çok görev ve görev zamanlayıcı
Aşağıda, TaskScheduler.Current
, Task.Run
ve tahıl bağlamından çıkmak ve ona nasıl geri dönülmesini göstermek için özel bir zamanlayıcının kullanıldığı örnek kod yer almaktadır.
public async Task MyGrainMethod()
{
// Grab the grain's task scheduler
var orleansTS = TaskScheduler.Current;
await Task.Delay(10_000);
// Current task scheduler did not change, the code after await is still running
// in the same task scheduler.
Assert.AreEqual(orleansTS, TaskScheduler.Current);
Task t1 = Task.Run(() =>
{
// This code runs on the thread pool scheduler, not on Orleans task scheduler
Assert.AreNotEqual(orleansTS, TaskScheduler.Current);
Assert.AreEqual(TaskScheduler.Default, TaskScheduler.Current);
});
await t1;
// We are back to the Orleans task scheduler.
// Since await was executed in Orleans task scheduler context, we are now back
// to that context.
Assert.AreEqual(orleansTS, TaskScheduler.Current);
// Example of using Task.Factory.StartNew with a custom scheduler to escape from
// the Orleans scheduler
Task t2 = Task.Factory.StartNew(() =>
{
// This code runs on the MyCustomSchedulerThatIWroteMyself scheduler, not on
// the Orleans task scheduler
Assert.AreNotEqual(orleansTS, TaskScheduler.Current);
Assert.AreEqual(MyCustomSchedulerThatIWroteMyself, TaskScheduler.Current);
},
CancellationToken.None,
TaskCreationOptions.None,
scheduler: MyCustomSchedulerThatIWroteMyself);
await t2;
// We are back to Orleans task scheduler.
Assert.AreEqual(orleansTS, TaskScheduler.Current);
}
Örnek: İş parçacığı havuzundaki bir iş parçacığında çalışan koddan bir grain çağrısı yapma
Başka bir senaryoda, tahıla ait görev zamanlama modelinden çıkıp bir iş parçacığı havuzu iş parçacığında (veya bir tane olmayan başka bir bağlamda) çalışması gereken, ancak yine de başka bir tahılı çağırması gereken tahıl kodu yer alır. Tahıl çağrıları, ek tören yapılmadan, tahılsız bağlamlardan yapılabilir.
Aşağıdaki kod, bir grain içinde çalışan ancak grain bağlamında olmayan bir koddan grain çağrısı yapmayı gösterir.
public async Task MyGrainMethod()
{
// Grab the Orleans task scheduler
var orleansTS = TaskScheduler.Current;
var fooGrain = this.GrainFactory.GetGrain<IFooGrain>(0);
Task<int> t1 = Task.Run(async () =>
{
// This code runs on the thread pool scheduler,
// not on Orleans task scheduler
Assert.AreNotEqual(orleansTS, TaskScheduler.Current);
int res = await fooGrain.MakeGrainCall();
// This code continues on the thread pool scheduler,
// not on the Orleans task scheduler
Assert.AreNotEqual(orleansTS, TaskScheduler.Current);
return res;
});
int result = await t1;
// We are back to the Orleans task scheduler.
// Since await was executed in the Orleans task scheduler context,
// we are now back to that context.
Assert.AreEqual(orleansTS, TaskScheduler.Current);
}
Kitaplıklarla çalışma
Kod tarafından kullanılan bazı harici kütüphaneler dahili olarak ConfigureAwait(false)
kullanabilir. .NET'te genel amaçlı kitaplıkları uygularken ConfigureAwait(false)
kullanmak iyi ve doğru bir uygulamadır. Bu, Orleans için bir sorun değildir. Kütüphane yöntemini çağıran grain kodu, normal bir await
kütüphane çağrısı beklediği sürece doğru olur. Sonuç tam olarak istenen şekilde olur: Kitaplık kodu, varsayılan zamanlayıcıda devamlılıkları çalıştırır (tarafından döndürülen TaskScheduler.Default
değer, genellikle önceki iş parçacığında çizili oldukları için sürekliliklerin bir ThreadPool iş parçacığında çalıştırılmasını garanti etmez), tahıl kodu ise tahılın zamanlayıcısında çalışır.
Sık sorulan bir diğer soru, kitaplık çağrılarının ile Task.Run
yürütülmesi gerekip gerekmediğidir; yani kitaplık kodunun ThreadPool
'a açıkça yük boşaltması gerekip gerekmediğidir (örn. await Task.Run(() => myLibrary.FooAsync())
). Yanıt hayır. Kodu ThreadPool
'a aktarmak, sadece kitaplık kodu zaman uyumlu çağrıları engelleyici şekilde çalışıyorsa gereklidir. Genellikle, iyi yazılmış ve doğru bir .NET zaman uyumsuz kitaplık (konumlarına Task
döndüren ve adında Async
soneki bulunan yöntemler) engelleyici çağrılar yapmaz. Bu nedenle, zaman uyumsuz kitaplığın hatalı olduğundan şüpheleniliyorsa veya zaman uyumlu bir engelleme kitaplığı bilinçli bir şekilde kullanılıyorsa, herhangi bir şeyin ThreadPool
öğesine aktarılması gerekmez.
Kilitlenmeler
Tanecikler tek iş parçacığında çalıştırıldığından, bir taneciği kilitli duruma getirmek mümkündür; bu, birden fazla iş parçacığının engelini kaldırmasını gerektiren bir yöntemle zaman uyumlu bir şekilde engellenerek yapılabilir. Bu, aşağıdaki yöntem ve özelliklerden herhangi birini çağıran kodun, sağlanan görevler yöntemin veya özelliğin çağrılma anına kadar tamamlanmadığında grain nesnesinin kilitlenmesine neden olabileceği anlamına gelir.
Task.Wait()
Task.Result
Task.WaitAny(...)
Task.WaitAll(...)
task.GetAwaiter().GetResult()
Düşük performansa ve tutarsızlığa yol açabilecekleri için herhangi bir yüksek eşzamanlılık hizmetinde bu yöntemlerden kaçının. .NET'i, yararlı işler gerçekleştirebilecek iş parçacıklarını engelleyerek aç bırakıyorlar ve tamamlanması için ThreadPool
'nin ek iş parçacıkları eklemesini gerektiriyorlar. Tahıl kodu yürütülürken, bu yöntemler tahılın kilitlenmesine neden olabilir, bu nedenle bunları tahıl kodu içinde kullanmaktan kaçının.
Bazı senkronizasyon-üstü-asenkron işler kaçınılmazsa, bu işleri ayrı bir zamanlayıcıya taşımak en iyi yoldur. En basit yol, örneğin kullanmaktır await Task.Run(() => task.Wait())
.
Sync-over-async çalışmalarından kaçınılmasının şiddetle tavsiye edildiğini, çünkü bunun uygulama ölçeklenebilirliğine ve performansına zarar verdiğini unutmayın.
Özet: Orleans'de görevlerle çalışma
Ne yapmaya çalışıyorsunuz? | Nasıl yapılır |
---|---|
.NET iş parçacığı havuzu iş parçacıklarında arka plan çalışması çalıştırın. Tahıl kodu veya taneli çağrılara izin verilmez. | Task.Run |
Sıra tabanlı eşzamanlılık garantileriyle Orleans zaman uyumsuz çalışan görevini tahıl kodundan çalıştırın (yukarıya bakın). |
Task.Factory.StartNew(WorkerAsync).Unwrap() (Unwrap) |
Zaman uyumlu çalışan görevini sıra tabanlı eşzamanlılık garantileriyle Orleans tahıl kodundan çalıştırın. | Task.Factory.StartNew(WorkerSync) |
İş öğelerini yürütmek için zaman aşımları | Task.Delay + Task.WhenAny |
Zaman uyumsuz kitaplık yöntemini çağırma |
await kitaplık çağrısı |
async
/
await komutunu kullanma |
Normal .NET Görev-Zaman Uyumsuz programlama modeli. Desteklenen ve önerilen |
ConfigureAwait(false) |
Tahıl kodunun içinde kullanmayın. Yalnızca kitaplıkların içinde izin verilir. |