簡體   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