繁体   English   中英

使用任务从静态main方法运行连续任务?

[英]Run a continuous task from static main method using tasks?

我正在尝试将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);
            }
        }
    }
}

如何确保任务在正确的线程上运行,甚至根本没有运行?

execute应该是运行时间较长的数据库摘要查询。 毫秒预计在几秒到几分钟的范围内,并希望计时的准确性。

“正确的线程”是指任务应在异步/网络环境中执行,而不是与主程序分发同步。

但是,如果可以重复使用此代码,有时可能需要在UI线程或服务器线程中运行任务,并且如果能解释该线程以及如何配置它,我将不胜感激。

您实际上从未启动过任务。 确实,恕我直言,将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() 我已在上面的版本中将其删除。

我有以下内容,但它永远永久停止,而无需运行操作(printStuff)。

发生这种情况是因为您传递给executeEvety的Task是使用'Task'构造函数创建的,因此,如果您未显式运行它,则不会安排它运行,因此等待您等待未启动的任务完成-这永远不会发生。

相反,您应该将Action传递给executeEvery,并在每次循环迭代时都调用它,而无需异步调用:

ExecuteEvery(action, 5000).Wait();

private static async Task ExecuteEvery(Action action, int milliseconds)
{
    while (true)
    {
        await Task.Delay(milliseconds);
        action();
    }
}

如果动作是长时间运行的。 如果您想在后台运行它,而不必等到下一次迭代(触发并忘记)之前完成, Task.Run在调用它时添加Task.Run

private static async Task ExecuteEvery(Action action, int milliseconds)
{
    while (true)
    {
        await Task.Delay(milliseconds);
        Task.Run(() => action());
    }
}

但是,忘了无休止的循环并使用Timer实现您想要的效果会更好吗?

创建Task不会自动启动它。 您正在等待一个由于尚未启动而永远不会完成的Task 您应该使用Task.Run()启动Task我在下面修改了您的代码:

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));
    }
}

我最终通过使用Func<Task>而不是Action<Task>

这样就可以使用async方法而不是函数,并且可以使用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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM