Cho đến bây giờ tôi sử dụng một nhiệm vụ LongRunning TPL cho CPU cyclic ràng buộc công việc nền thay vì bộ đếm thời gian luồng, vì:
- nhiệm vụ TPL hỗ trợ hủy
- bộ đếm thời gian luồng có thể bắt đầu một chủ đề trong khi programm tắt nguồn gây ra các vấn đề có thể xảy ra với các tài nguyên được xử lý
- cơ hội bị tràn: bộ đếm luồng có thể bắt đầu một luồng khác trong khi trước đó vẫn đang được xử lý do công việc lâu dài bất ngờ (tôi biết, nó có thể được ngăn chặn bằng cách dừng và khởi động lại bộ hẹn giờ)
Tuy nhiên, giải pháp TPL luôn xác nhận một chuỗi chuyên dụng không cần thiết trong khi chờ hành động tiếp theo (phần lớn thời gian). Tôi muốn sử dụng giải pháp được đề xuất của Jeff để thực hiện công việc cyclic CPU bị ràng buộc trên nền bởi vì nó chỉ cần một thread threadpool khi có công việc để làm đó là tốt hơn cho khả năng mở rộng (đặc biệt là khi khoảng thời gian là lớn).
Để đạt được điều đó, tôi sẽ đề nghị 4 adaptions:
- Thêm
ConfigureAwait(false)
đến Task.Delay()
để thực hiện doWork
hành động trên một sợi bơi thread, nếu không doWork
sẽ được thực hiện trên các thread kêu gọi mà không phải là ý tưởng song song
- Stick với mẫu hủy bằng cách ném một TaskCanceledException (vẫn còn cần thiết?)
- Chuyển tiếp các CancellationToken để
doWork
để kích hoạt nó để hủy bỏ nhiệm vụ
- Thêm một tham số của loại đối tượng để cung cấp thông tin trạng thái công việc (như một nhiệm vụ TPL)
Về điểm 2 Tôi không chắc chắn, không async chờ đợi vẫn đòi hỏi sự TaskCanceledExecption hoặc là nó chỉ thực hành tốt nhất?
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);
}
Xin vui lòng cho ý kiến của bạn với các giải pháp đề xuất ...
Cập nhật 2016-8-30
Các giải pháp trên không ngay lập tức gọi doWork()
nhưng bắt đầu với await Task.Delay().ConfigureAwait(false)
để đạt được công tắc chủ đề cho doWork()
. Giải pháp dưới đây khắc phục vấn đề này bằng cách gói cuộc gọi doWork()
đầu tiên vào số Task.Run()
và chờ nó.
Dưới đây là thay thế async \ await đang chờ cải tiến cho Threading.Timer
thực hiện công việc tuần hoàn có thể hủy và có thể mở rộng (so với giải pháp TPL) vì nó không chiếm bất kỳ chủ đề nào trong khi chờ hành động tiếp theo.
Lưu ý rằng ngược lại với Bộ hẹn giờ, thời gian chờ (period
) là không đổi và không phải là thời gian chu kỳ; thời gian chu kỳ là tổng thời gian chờ đợi và thời lượng doWork()
có thể thay đổi.
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);
}
Bạn nên sử dụng Bộ hẹn giờ bên trong Tác vụ thay vì sử dụng cơ chế Thread.Sleep. Nó hiệu quả hơn. –