Bunun için TPL Dataflow'u kullanırım (çünkü .NET 4.5'i kullanıyorsunuz ve Taskdahili olarak kullanıyor ). ActionBlock<TInput>İşlemi işlendikten ve uygun bir süre bekledikten sonra kendisine öğeleri gönderen bir öğeyi kolayca oluşturabilirsiniz .
Öncelikle, hiç bitmeyen görevinizi yaratacak bir fabrika oluşturun:
ITargetBlock<DateTimeOffset> CreateNeverEndingTask(
Action<DateTimeOffset> action, CancellationToken cancellationToken)
{
if (action == null) throw new ArgumentNullException("action");
ActionBlock<DateTimeOffset> block = null;
block = new ActionBlock<DateTimeOffset>(async now => {
action(now);
await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken).
ConfigureAwait(false);
block.Post(DateTimeOffset.Now);
}, new ExecutionDataflowBlockOptions {
CancellationToken = cancellationToken
});
return block;
}
ActionBlock<TInput>Bir DateTimeOffsetyapı almak için seçtim ; bir tür parametresi iletmeniz gerekir ve bu, bazı yararlı durumları da iletebilir (isterseniz, durumun doğasını değiştirebilirsiniz).
Ayrıca, ActionBlock<TInput>varsayılan olarak bir seferde yalnızca bir öğeyi işlediğini unutmayın , bu nedenle yalnızca bir eylemin işleneceği garanti edilir (yani, uzantı yöntemini kendi başına geri çağırdığında yeniden giriş yapmanız gerekmez ).Post
Ayrıca CancellationTokenyapıyı hem yapıcıya hem ActionBlock<TInput>de Task.Delayyöntem çağrısına geçirdim ; İşlem iptal edilirse, iptal mümkün olan ilk fırsatta gerçekleşecektir.
Oradan, uygulanan ITargetBlock<DateTimeoffset>arabirimi depolamak için kodunuzun yeniden düzenlenmesi kolaydır ActionBlock<TInput>(bu, tüketiciler olan blokları temsil eden üst düzey soyutlamadır ve Postuzantı yöntemine yapılan bir çağrı yoluyla tüketimi tetikleyebilmek istersiniz ):
CancellationTokenSource wtoken;
ActionBlock<DateTimeOffset> task;
Sizin StartWorkyöntemi:
void StartWork()
{
wtoken = new CancellationTokenSource();
task = CreateNeverEndingTask(now => DoWork(), wtoken.Token);
task.Post(DateTimeOffset.Now);
}
Ve sonra StopWorkyönteminiz:
void StopWork()
{
using (wtoken)
{
wtoken.Cancel();
}
wtoken = null;
task = null;
}
TPL Dataflow'u neden burada kullanmak istersiniz? Birkaç neden:
Endişelerin ayrılması
CreateNeverEndingTaskYöntem şimdi çok konuşmak için "hizmet" yaratan bir fabrikasıdır. Ne zaman başlayıp duracağını siz kontrol edersiniz ve tamamen bağımsızdır. Zamanlayıcının durum kontrolünü kodunuzun diğer yönleriyle iç içe geçirmeniz gerekmez. Basitçe bloğu yaratırsınız, başlatırsınız ve işiniz bittiğinde durdurursunuz.
İş parçacıkları / görevler / kaynakların daha verimli kullanımı
TPL veri akışındaki bloklar için varsayılan zamanlayıcı Task, iş parçacığı havuzu olan a için aynıdır . Kullanarak ActionBlock<TInput>Eyleminizi yanı sıra bir çağrı işlemek için Task.Delay, size aslında hiçbir şey yapmıyorsun kullanmakta olduğu iplik kontrolünü elde ediyoruz. Kabul Taskedilirse , bu aslında devamı işleyecek yeniyi ortaya çıkardığınızda bir miktar ek yüke yol açar , ancak bunu sıkı bir döngüde işlemediğiniz düşünülürse bu küçük olmalıdır (çağrılar arasında on saniye bekliyorsunuz).
Eğer DoWorkgerçekte (bir döndüren içinde, yani awaitable yapılabilir fonksiyonu Task), o zaman (muhtemelen) daha yukarıda fabrika yöntemini değişiklikler yaparak bu duruma bir almaya Func<DateTimeOffset, CancellationToken, Task>bir yerine Action<DateTimeOffset>, şöyle:
ITargetBlock<DateTimeOffset> CreateNeverEndingTask(
Func<DateTimeOffset, CancellationToken, Task> action,
CancellationToken cancellationToken)
{
if (action == null) throw new ArgumentNullException("action");
ActionBlock<DateTimeOffset> block = null;
block = new ActionBlock<DateTimeOffset>(async now => {
await action(now, cancellationToken).
ConfigureAwait(false);
await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken).
ConfigureAwait(false);
block.Post(DateTimeOffset.Now);
}, new ExecutionDataflowBlockOptions {
CancellationToken = cancellationToken
});
return block;
}
Elbette, CancellationTokenyönteminizi (eğer kabul ederse) burada yapmak iyi bir uygulama olacaktır .
Bu, daha sonra DoWorkAsyncaşağıdaki imzaya sahip bir yönteme sahip olacağınız anlamına gelir :
Task DoWorkAsync(CancellationToken cancellationToken);
StartWorkYönteme aktarılan yeni imzayı hesaba katmak için yöntemi değiştirmeniz gerekir (sadece biraz ve burada endişelerin ayrılmasını aklamazsınız), CreateNeverEndingTaskşöyle:
void StartWork()
{
wtoken = new CancellationTokenSource();
task = CreateNeverEndingTask((now, ct) => DoWorkAsync(ct), wtoken.Token);
task.Post(DateTimeOffset.Now, wtoken.Token);
}