运行 后台任务 (PCL)
Running a Task in the background (PCL)
我有一个 class 和 async
方法:
public static async Task GetData() { ... }
在我使用的应用程序框架中,我需要启动该进程并在应用程序启动时忘记它:
protected override void OnStart()
{
await MyService.GetData();
}
我做不到 OnStart
async.
如何在后台任务中启动它而忘记它?
I can't make OnStart Async. How do I start it in a background task and
forget about it?
为什么不呢?没有什么能阻止你成功 async
。 async
修饰符不影响 CLR 方法签名,即您可以重写 void
方法并使其成为 async
:
abstract class AppBase
{
protected abstract void OnStart();
}
class App: AppBase
{
public static async Task GetData() { await Task.Delay(1); }
protected override async void OnStart()
{
await GetData();
}
}
这样,如果 GetData
抛出,至少你会看到一个异常,这与其他答案所建议的不同。
确保您了解 async void
方法和 Task
错误处理的一般工作方式,this material 可能会有所帮助。
Task.Run( () => MyService.GetData() )
的一些其他问题:
因为 GetData
已经 异步,用 Task.Run
包装它没有什么意义。它通常仅在客户端 UI 应用程序中完成,并且仅当 GetData
具有长 运行 同步部分(在它达到第一个 await
之前)。否则,您也可以在没有 Task.Run
和没有 await
的情况下调用 GetData()
(这也是一个坏主意:在任何一种情况下,您都会进行一次即发即弃调用而不观察可能的异常)。
Task.Run
将在没有同步内容的随机池线程上启动 GetData
,这对于 UI 应用或 ASP.NET应用
如果您想触发此 async
操作并忘记它,您需要做的就是调用该方法而不等待返回的任务:
protected override void OnStart()
{
MyService.GetDataAsync();
}
但是,由于您没有观察任务,因此您永远不会知道它是否成功完成。
您应该保留对该任务的引用,并在以后 await
它:
public Task _dataTask;
protected override void OnStart()
{
_dataTask = MyService.GetDataAsync();
}
public Task AwaitInitializationAsync()
{
return _dataTask;
}
或者添加一个继续处理任何异常:
protected override void OnStart()
{
MyService.GetDataAsync().ContinueWith(t =>
{
try
{
t.Wait();
}
catch (Exception e)
{
// handle exceptions
}
});
}
您不应该将 Task.Run
用作 ,但是使用 async void
会更糟糕,因为 async void
方法(不是 UI 事件处理程序)将 拆除整个过程*.
您可以尝试创建方法 async void
,同时确保不会在其中使用 try-catch
块抛出任何异常:
protected override async void OnStart()
{
try
{
await GetData();
}
catch (Exception e)
{
// handle e.
}
}
但我仍然建议不要这样做,因为即使完全崩溃的可能性也很危险。
*您可以通过为 AppDomain.CurrentDomain.UnhandledException
注册偶数处理程序来解决这个问题,但这应该是最后的手段,而不是最佳实践
我有一个 class 和 async
方法:
public static async Task GetData() { ... }
在我使用的应用程序框架中,我需要启动该进程并在应用程序启动时忘记它:
protected override void OnStart()
{
await MyService.GetData();
}
我做不到 OnStart
async.
如何在后台任务中启动它而忘记它?
I can't make OnStart Async. How do I start it in a background task and forget about it?
为什么不呢?没有什么能阻止你成功 async
。 async
修饰符不影响 CLR 方法签名,即您可以重写 void
方法并使其成为 async
:
abstract class AppBase
{
protected abstract void OnStart();
}
class App: AppBase
{
public static async Task GetData() { await Task.Delay(1); }
protected override async void OnStart()
{
await GetData();
}
}
这样,如果 GetData
抛出,至少你会看到一个异常,这与其他答案所建议的不同。
确保您了解 async void
方法和 Task
错误处理的一般工作方式,this material 可能会有所帮助。
Task.Run( () => MyService.GetData() )
的一些其他问题:
因为
GetData
已经 异步,用Task.Run
包装它没有什么意义。它通常仅在客户端 UI 应用程序中完成,并且仅当GetData
具有长 运行 同步部分(在它达到第一个await
之前)。否则,您也可以在没有Task.Run
和没有await
的情况下调用GetData()
(这也是一个坏主意:在任何一种情况下,您都会进行一次即发即弃调用而不观察可能的异常)。Task.Run
将在没有同步内容的随机池线程上启动GetData
,这对于 UI 应用或 ASP.NET应用
如果您想触发此 async
操作并忘记它,您需要做的就是调用该方法而不等待返回的任务:
protected override void OnStart()
{
MyService.GetDataAsync();
}
但是,由于您没有观察任务,因此您永远不会知道它是否成功完成。
您应该保留对该任务的引用,并在以后 await
它:
public Task _dataTask;
protected override void OnStart()
{
_dataTask = MyService.GetDataAsync();
}
public Task AwaitInitializationAsync()
{
return _dataTask;
}
或者添加一个继续处理任何异常:
protected override void OnStart()
{
MyService.GetDataAsync().ContinueWith(t =>
{
try
{
t.Wait();
}
catch (Exception e)
{
// handle exceptions
}
});
}
您不应该将 Task.Run
用作 async void
会更糟糕,因为 async void
方法(不是 UI 事件处理程序)将 拆除整个过程*.
您可以尝试创建方法 async void
,同时确保不会在其中使用 try-catch
块抛出任何异常:
protected override async void OnStart()
{
try
{
await GetData();
}
catch (Exception e)
{
// handle e.
}
}
但我仍然建议不要这样做,因为即使完全崩溃的可能性也很危险。
*您可以通过为 AppDomain.CurrentDomain.UnhandledException
注册偶数处理程序来解决这个问题,但这应该是最后的手段,而不是最佳实践