结束时重复调用 C# 任务
Call C# Task Repeatedly on conclusion
我有一个 C# 应用程序,它必须 运行 并行代码块。这是其中两个代码块的基本结构。实际上,还会有更多。
private async Task MyFirstTask()
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
其中一些代码块将 运行 计时。有些会 运行 重复。为了完成,我有以下内容:
Task.Run(() => MyFirstTask());
Task.Run(() => MySecondTask());
MyFirstTask
完成后,我想再次 运行。事实上,我想一遍又一遍地 运行 它,直到程序停止。然而,我希望 MySecondTask
到 运行 与 MyFirstTask
并行。我的问题是,如何重复执行 MyFirstTask
,同时仍然与 MySecondTask
并行?
我回顾了几个相关的 SO 问题。我也没有看到 Complete
类型的事件处理程序。所以,我对如何实现这个有点迷茫。感谢您的帮助!
async/await
的美妙之处在于您可以像编写同步代码一样编写异步代码。您将如何重复同步操作?你可以使用一个循环。你可以在这里做同样的事情,例如:
private async Task MyFirstTask(CancellationToken token) {
while (!token.IsCancellationRequested) {
// do stuff
await FirstTaskImplementation();
// cleanup
}
}
您可以将循环嵌入到当前方法中或将其提升到包装方法中,但无论哪种方式都应该有效。
您可以继续按照与现在相同的方式安排任务,但您确实应该 await
您的 async
方法:
CancellationTokenSource cts = new CancellationTokenSource();
Task.Run(async () => await MyFirstTask(cts.Token));
Task.Run(async () => await MySecondTask());
// Request cancellation via `cts` when you want the looping to end.
虽然你没有询问,但如果你想在每次迭代之间插入一个延迟,你可以简单地在循环体的末尾放置一个 await Task.Delay(...)
语句。
您不一定需要为第一个任务使用 Task.Run
。您可以对第一个任务使用 Timer,将 AutoReset
设置为 true
。这样它就会 运行 永远存在,你就不用再担心了。
private static System.Timers.Timer aTimer;
public static void Main()
{
SetTimer(); //MyFirstTask starts running over and over in another thread
Task.Run(() => MySecondTask());
}
private static void SetTimer()
{
// Create a timer with a 1ms interval (has to be > 0)
aTimer = new System.Timers.Timer(1);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += MyFirstTask;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static async void MyFirstTask(Object source, ElapsedEventArgs e)
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
另一种方法是这样的:
var first=MyFirstTask().ToObservable();
var second=MySecondTask().ToObservable();
first.Repeat().Merge(second).Subscribe(x=>Console.WriteLine("Task completing."));
那是说明性的,未经测试的代码。如果您希望 MySecondTask 完成,那么可能是这样:
first.Repeat().TakeUntil(second).Subscribe(x=>Console.WriteLine("Task completing."));
如果您想将超时添加到秒,您可以这样做:
first.Repeat().TakeUntil(second.Timeout(TimeSpan.FromMilliseconds(100))).Subscribe(...)
如果您想在每个任务完成时显示一些内容,请将可观察对象声明为:
var first=MyFirstTask().ToObservable().Do(Console.WriteLine("First completing"));
以上需要 System.Reactive.Linq 个命名空间。我发现这些基于 Rx 的并发解决方案通常比 TPL 更优雅,但这只是主观的。
最后,如果您不想在订阅被调用之前开始任务,或者某些内容已准备好开始观看,您可以使用 Observable.FromAsync , as per info here
我有一个 C# 应用程序,它必须 运行 并行代码块。这是其中两个代码块的基本结构。实际上,还会有更多。
private async Task MyFirstTask()
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
其中一些代码块将 运行 计时。有些会 运行 重复。为了完成,我有以下内容:
Task.Run(() => MyFirstTask());
Task.Run(() => MySecondTask());
MyFirstTask
完成后,我想再次 运行。事实上,我想一遍又一遍地 运行 它,直到程序停止。然而,我希望 MySecondTask
到 运行 与 MyFirstTask
并行。我的问题是,如何重复执行 MyFirstTask
,同时仍然与 MySecondTask
并行?
我回顾了几个相关的 SO 问题。我也没有看到 Complete
类型的事件处理程序。所以,我对如何实现这个有点迷茫。感谢您的帮助!
async/await
的美妙之处在于您可以像编写同步代码一样编写异步代码。您将如何重复同步操作?你可以使用一个循环。你可以在这里做同样的事情,例如:
private async Task MyFirstTask(CancellationToken token) {
while (!token.IsCancellationRequested) {
// do stuff
await FirstTaskImplementation();
// cleanup
}
}
您可以将循环嵌入到当前方法中或将其提升到包装方法中,但无论哪种方式都应该有效。
您可以继续按照与现在相同的方式安排任务,但您确实应该 await
您的 async
方法:
CancellationTokenSource cts = new CancellationTokenSource();
Task.Run(async () => await MyFirstTask(cts.Token));
Task.Run(async () => await MySecondTask());
// Request cancellation via `cts` when you want the looping to end.
虽然你没有询问,但如果你想在每次迭代之间插入一个延迟,你可以简单地在循环体的末尾放置一个 await Task.Delay(...)
语句。
您不一定需要为第一个任务使用 Task.Run
。您可以对第一个任务使用 Timer,将 AutoReset
设置为 true
。这样它就会 运行 永远存在,你就不用再担心了。
private static System.Timers.Timer aTimer;
public static void Main()
{
SetTimer(); //MyFirstTask starts running over and over in another thread
Task.Run(() => MySecondTask());
}
private static void SetTimer()
{
// Create a timer with a 1ms interval (has to be > 0)
aTimer = new System.Timers.Timer(1);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += MyFirstTask;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static async void MyFirstTask(Object source, ElapsedEventArgs e)
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
另一种方法是这样的:
var first=MyFirstTask().ToObservable();
var second=MySecondTask().ToObservable();
first.Repeat().Merge(second).Subscribe(x=>Console.WriteLine("Task completing."));
那是说明性的,未经测试的代码。如果您希望 MySecondTask 完成,那么可能是这样:
first.Repeat().TakeUntil(second).Subscribe(x=>Console.WriteLine("Task completing."));
如果您想将超时添加到秒,您可以这样做:
first.Repeat().TakeUntil(second.Timeout(TimeSpan.FromMilliseconds(100))).Subscribe(...)
如果您想在每个任务完成时显示一些内容,请将可观察对象声明为:
var first=MyFirstTask().ToObservable().Do(Console.WriteLine("First completing"));
以上需要 System.Reactive.Linq 个命名空间。我发现这些基于 Rx 的并发解决方案通常比 TPL 更优雅,但这只是主观的。
最后,如果您不想在订阅被调用之前开始任务,或者某些内容已准备好开始观看,您可以使用 Observable.FromAsync , as per info here