我试图将async / await引入新的代码库,让它每隔x秒执行一次后台任务。
我已经得到了以下内容,但它只是在没有运行动作(printStuff)的情况下永远停止。
using System;
using System.Threading.Tasks;
namespace ASyncTaskDemo
{
class Program3
{
public static void Main(string[] args)
{
Action action = printStuff;
ExecuteEvery(new Task(action), 5000).Wait();
//simulate the rest of the application stalling until shutdown events.
Console.ReadLine();
}
private static int x = 0;
private static void printStuff()
{
Console.Error.Write(x++);
}
private static async Task ExecuteEvery(Task execute, int milliseconds)
{
while (true)
{
var delay = Task.Delay(milliseconds);
await Task.WhenAll(delay, execute);
}
}
}
}
如何确保任务在正确的线程上运行,甚至可以运行?
执行应该是一个长期运行的数据库摘要查询。 毫秒预计在几秒到几分钟的范围内,并且会提高计时的准确性。
通过正确的线程'我的意思是任务应该在异步/网络环境中执行,而不是与主程序调度同步。
但是,如果要重用此代码,有时候在UI线程或服务器线程中运行任务是合适的,如果解释了什么线程以及如何配置它,我将不胜感激。< / p>
答案 0 :(得分:2)
你永远不会真正开始任务。实际上,恕我直言,将execute
表示为一项任务是没有意义的。只需传递代表本身:
class Program3
{
public static void Main(string[] args)
{
Action action = printStuff;
ExecuteEvery(action, 5000); // ignore returned task
//simulate the rest of the application stalling until shutdown events.
Console.ReadLine();
}
private static int x = 0;
private static void printStuff()
{
Console.Error.Write(x++);
}
private static async Task ExecuteEvery(Action execute, int milliseconds)
{
while (true)
{
await Task.Delay(milliseconds);
execute();
}
}
}
另请注意,如果您致电Wait()
,则永远不会阅读ReadLine()
。我在上面的版本中删除了它。
答案 1 :(得分:2)
我已经得到了以下内容,但它永远不会永远停滞 运行动作(printStuff)。
这是因为您传递给executeEvety的Task
是使用&#39;任务&#39;创建的。构造函数,因此如果你没有明确地运行它,它就不会安排运行,所以等待你等待一个未启动的任务完成 - 这将永远不会发生。
您应该将Action
传递给executeEvery并在每次循环迭代时调用它,而不需要异步调用:
ExecuteEvery(action, 5000).Wait();
private static async Task ExecuteEvery(Action action, int milliseconds)
{
while (true)
{
await Task.Delay(milliseconds);
action();
}
}
如果动作是长时间运行的话。你想在后台运行它而不等待它在下一次迭代之前完成(火与忘记),当你调用它时添加Task.Run
:
private static async Task ExecuteEvery(Action action, int milliseconds)
{
while (true)
{
await Task.Delay(milliseconds);
Task.Run(() => action());
}
}
但是,忘记无限循环并使用Timer来达到你想要的效果会不会更好?
答案 2 :(得分:1)
创建Task
不会自动启动它。您正在等待永远无法完成的Task
,因为它尚未启动。您应该使用Task
开始Task.Run()
我已经修改了您的代码:
public static void Main(string[] args)
{
Action action = printStuff;
ExecuteEvery(action, 5000).Wait();
//simulate the rest of the application stalling until shutdown events.
Console.ReadLine();
}
private static int x = 0;
private static void printStuff()
{
Console.Error.Write(x++);
}
private static async Task ExecuteEvery(Action execute, int milliseconds)
{
while (true)
{
var delay = Task.Delay(milliseconds);
await Task.WhenAll(delay, Task.Run(execute));
}
}
答案 3 :(得分:0)
我最后使用Func<Task>
代替Action<Task>
这允许使用异步方法而不是函数,并允许使用async关键字适当地修饰其他方法。
/// <summary>
/// Executes a task every x milliseconds, but will wait for long running tasks to complete.
/// </summary>
/// <param name="execute">A Task Producer</param>
/// <param name="milliseconds">How often to run execute</param>
/// <param name="cancel">A cancellation token</param>
/// <returns></returns>
private async Task ExecuteEvery(Func<Task> execute, int milliseconds, CancellationToken cancel)
{
while (true)
{
var delay = Task.Delay(milliseconds, cancel);
await Task.WhenAll(delay, execute());
if(cancel.IsCancellationRequested) break;
}
}