Şimdiye kadar iş parçacığı zamanlayıcı yerine döngüsel CPU'ya bağlı arka plan çalışması için bir LongRunning TPL görevi kullandım, çünkü:
- TPL görevi iptali destekler
- iş parçacığı zamanlayıcısı, program kapanırken başka bir iş parçacığı başlatabilir ve atılan kaynaklarla olası sorunlara neden olabilir
- taşma şansı: iş parçacığı zamanlayıcı, beklenmedik uzun çalışma nedeniyle önceki işlenirken başka bir iş parçacığı başlatabilir (biliyorum, zamanlayıcıyı durdurup yeniden başlatarak önlenebilir)
Bununla birlikte, TPL çözümü her zaman, bir sonraki eylemi beklerken (çoğu zaman bu) gerekli olmayan özel bir iş parçacığı talep eder. Arka planda CPU'ya bağlı döngüsel çalışma gerçekleştirmek için Jeff'in önerilen çözümünü kullanmak istiyorum, çünkü ölçeklenebilirlik için daha iyi olan, yapılacak iş olduğunda yalnızca bir iş parçacığı iş parçacığına ihtiyaç duyar (özellikle aralık dönemi büyük olduğunda).
Bunu başarmak için 4 uyarlama öneririm:
- Ekle
ConfigureAwait(false)
için Task.Delay()
yürütülecek doWork
bir iş parçacığı havuzu iş parçacığı üzerinde eylem aksi doWork
paralellik fikri olmadığı çağıran iş parçacığı üzerinde yapılacak
- Bir TaskCanceledException oluşturarak iptal modeline bağlı kalın (yine de gerekli mi?)
doWork
Görevi iptal etmesini sağlamak için CancellationToken'ı iletin
- Görev durumu bilgilerini sağlamak için nesne türünde bir parametre ekleyin (bir TPL görevi gibi)
2. nokta hakkında emin değilim, eşzamansız bekleme hala TaskCanceledExecption gerektiriyor mu yoksa sadece en iyi uygulama mı?
public static async Task Run(Action<object, CancellationToken> doWork, object taskState, TimeSpan period, CancellationToken cancellationToken)
{
do
{
await Task.Delay(period, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
doWork(taskState, cancellationToken);
}
while (true);
}
Lütfen önerilen çözüme yorumlarınızı yazın ...
2016-8-30 Güncellemesi
Yukarıdaki çözüm hemen aramaz, doWork()
ancak await Task.Delay().ConfigureAwait(false)
iş parçacığı anahtarını elde etmek için başlar doWork()
. Aşağıdaki çözüm, ilk doWork()
aramayı a karakterine sararak ve bekleyerek bu sorunun üstesinden Task.Run()
gelir.
Aşağıda, Threading.Timer
iptal edilebilir döngüsel çalışma gerçekleştiren ve ölçeklenebilir olan (TPL çözümüne kıyasla), bir sonraki eylemi beklerken herhangi bir iş parçacığı işgal etmediği için iyileştirilmiş zaman uyumsuz \ bekleme değiştirme yer almaktadır.
Zamanlayıcının aksine, bekleme süresinin ( period
) sabit olduğunu ve döngü süresinin olmadığını unutmayın; döngü süresi, bekleme süresinin toplamıdır ve süresi doWork()
değişebilir.
public static async Task Run(Action<object, CancellationToken> doWork, object taskState, TimeSpan period, CancellationToken cancellationToken)
{
await Task.Run(() => doWork(taskState, cancellationToken), cancellationToken).ConfigureAwait(false);
do
{
await Task.Delay(period, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
doWork(taskState, cancellationToken);
}
while (true);
}