C# 异步操作的循环调用模式
我想定期执行一些基于I/O的异步操作。 它不应该运行得尽可能快,而是在两个周期之间有一个可配置的延迟 到目前为止,我提出了两种不同的方法,我想知道哪一种在资源消费方面更好 使用Task.Run()接近1 用这种方法包装在C# 异步操作的循环调用模式,c#,event-handling,task,C#,Event Handling,Task,我想定期执行一些基于I/O的异步操作。 它不应该运行得尽可能快,而是在两个周期之间有一个可配置的延迟 到目前为止,我提出了两种不同的方法,我想知道哪一种在资源消费方面更好 使用Task.Run()接近1 用这种方法包装在Task.Run()中是不必要的,但是这样更好吗 我为这两种方法创建了一个.Net控制台应用程序,并在几分钟内记录了以下性能计数器,老实说,没有看到太大的差异: \处理(事件)%处理器时间(接近高出2~20%) \进程(事件)\Private字节(几乎相等,接近2 slighlt
Task.Run()
中是不必要的,但是这样更好吗
我为这两种方法创建了一个.Net控制台应用程序,并在几分钟内记录了以下性能计数器,老实说,没有看到太大的差异:
使用这些计数器时,我是否忽略了要点?这两个计数器实际上在做相同的事情。事件选项似乎增加了不必要的复杂性。资源消耗差异不显著 更合适的选择是使用or。这使得代码更容易阅读和理解,因为它表达了意图。在幕后,所有的备选方案或多或少都会产生相同的结果
你需要考虑一下你是如何计算时间的。执行时间是否应包含在计时间隔中?通常间隔比执行时间长得多,所以这无关紧要。如果有关系,您可能需要将计时器设置为仅触发一次,并在操作完成后设置计时器。根据公认的答案,以下是我的新方法:
internal class EventHandlerService
{
private Timer _timer;
private TimeSpan refreshTime = TimeSpan.FromSeconds(5);
public void Start()
{
_timer = new Timer(Communicate, null, 0,(int)refreshTime.TotalMilliseconds);
}
private void Communicate(object stateInfo)
{
Task.Run(async () =>
{
_timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); // stop the timer
Console.WriteLine($"Starting at {DateTime.UtcNow.ToString("O")}");
var stopWatch=new Stopwatch();
stopWatch.Start();
try
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
catch (Exception ex)
{
}
finally
{
Console.WriteLine($"Finishing at {DateTime.UtcNow.ToString("O")} after: {stopWatch.Elapsed}");
var dueTime = refreshTime.Subtract(stopWatch.Elapsed);
Console.WriteLine($"Calced dueTime to: {dueTime.TotalSeconds} at {DateTime.UtcNow.ToString("O")}");
_timer.Change(Math.Max((int) dueTime.TotalMilliseconds, 0), (int)refreshTime.TotalMilliseconds); // start the timer
}
});
}
}
通过这种方法,我满足了自己的需求:
实际刷新/计时器周期从不低于5秒,但如果处理程序的时间超过5秒,则会立即触发下一次执行。唯一的问题是:如果事件处理程序的时间超过间隔时间,则我不想“排队”我的事件处理程序,而只是立即触发下一次执行。应该承认,在一个处理器上只有一个on处理程序time@yBother然后使用threading.Timer并在每次任务完成时调用
.Change
,无限期。另一种选择是一个简单的循环,它启动您的工作并调用任务。延迟
,这比伪递归任务更具可读性。我找不到使线程化的方法。计时器只触发一次?@yBother阅读的文档。更改
“期间。。。指定System.Threading.InfinitieTimeSpan以禁用周期信号“即-1。
internal class CommunicationService
{
private event EventHandler CommunicationHandler;
private readonly HttpClient _httpClient = new HttpClient(new HttpClientHandler());
public void Start()
{
CommunicationHandler = (o, events) => Communicate();
OnCommunicationTriggered();
}
private async void Communicate()
{
try
{
var result = await _httpClient.GetAsync(someUri);
await Task.Delay(TimeSpan.FromSeconds(configurableValue));
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
OnCommunicationTriggered();
}
OnCommunicationTriggered();
}
private void OnCommunicationTriggered()
{
CommunicationHandler.Invoke(this, EventArgs.Empty);
}
}
internal class EventHandlerService
{
private Timer _timer;
private TimeSpan refreshTime = TimeSpan.FromSeconds(5);
public void Start()
{
_timer = new Timer(Communicate, null, 0,(int)refreshTime.TotalMilliseconds);
}
private void Communicate(object stateInfo)
{
Task.Run(async () =>
{
_timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); // stop the timer
Console.WriteLine($"Starting at {DateTime.UtcNow.ToString("O")}");
var stopWatch=new Stopwatch();
stopWatch.Start();
try
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
catch (Exception ex)
{
}
finally
{
Console.WriteLine($"Finishing at {DateTime.UtcNow.ToString("O")} after: {stopWatch.Elapsed}");
var dueTime = refreshTime.Subtract(stopWatch.Elapsed);
Console.WriteLine($"Calced dueTime to: {dueTime.TotalSeconds} at {DateTime.UtcNow.ToString("O")}");
_timer.Change(Math.Max((int) dueTime.TotalMilliseconds, 0), (int)refreshTime.TotalMilliseconds); // start the timer
}
});
}
}