[英]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.