我有幾百個設備,我需要每隔5秒檢查一次他們的狀態。高性能異步監控任務
我使用的API包含調用一個DLL,並返回一個單一的設備
string status = ReadStatus(int deviceID); // waits here until the status is returned
上述功能通常返回在幾個毫秒的狀態的狀態被卡死,但會有我可能無法獲得第二個或更多狀態的情況!或者更糟的是,一個設備可能根本沒有響應。
因此,我需要引入一種異步的形式,以確保一個不響應的設備不會影響所有其他被監視的設備。
我目前的做法是如下
// triggers every 5 sec
public MonitorDevices_ElapsedInterval(object sender, ElapsedEventArgs elapsedEventArgs)
{
foreach (var device in lstDevices) // several hundred devices in the list
{
var task = device.ReadStatusAsync(device.ID, cts.Token);
tasks.Add(task);
}
// await all tasks finished, or timeout after 4900ms
await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(4900, cts.Token));
cts.Cancel();
var devicesThatResponded = tasks.Where(t => t.Status == TaskStatus.RanToCompletion)
.Select(t => t.GetAwaiter().GetResult())
.ToList();
}
及以下
public async Task ReadStatusAsync(int deviceID, CancellationToken tk)
{
await Task.Delay(50, tk);
// calls the dll to return the status. Blocks until the status is return
Status = ReadStatus(deviceID);
}
我有我的代碼的幾個問題的設備類
- 的foreach循環火災同時執行幾百個任務,與此同時回調e Task.Delay由線程池中的線程提供服務,每個任務需要幾個ms。
我認爲這是一個很大的潛在瓶頸。有沒有更好的方法?
這可能是類似於斯蒂芬·克利裏評論在這裏,但他沒有提供一種替代What it costs to use Task.Delay()?
如果ReadStatus未能歸還,我想使用取消令牌取消坐在那裏等待響應的線程...這似乎不起作用。
等待Task.Delay(50,TK)
了Thread.Sleep(100000)//模擬設備不響應
我仍然有大約20個工作線程活着(即使我期待CTS .Cancel()要殺死他們。
謝謝。如果我在API中有一個ReadStatusAsync,那麼使用Task.Delay的當前實現是否有效? 和每個設備使用一個單獨的計時器的現貨,應該有這個想法! – RaduTomy
@RaduTomy:我看不到需要'Task.Delay'。如果它是異步的,則調用它並「等待」;如果它是同步的(並且你需要一個單獨的線程),然後通過Task.Run調用它。如果你使用每個設備的計時器(按照建議),你不應該需要'Task.Run'。 –
好的,我很清楚。謝啦! – RaduTomy