管理具有不同输出的任务
Managing Tasks with different outputs
我有一个 .NET Core 2.1 项目,它有一个 BackgroundService
,我希望它的职责只是处理记录来自一组不同任务的结果,这些任务可以 return 不同的值。我想将他们的所有输出分组到任务管理器 class 中以记录他们的输出。是否有可能有一个 List<Task>
将包含来自这些异步方法的所有 Task
对象?
我不想为每个要 await
的方法设置多个 Task
字段。我宁愿将它们放入某种 List
中,因为可能会有比我希望此管理器管理的这三种异步方法更多的方法。
我正在考虑做类似的事情:
public class MyTaskManager : BackgroundService
{
private readonly ILogger<MyTaskManager> _logger;
private APIInvoker _invoker;
public MyTaskManager (ILogger<MyTaskManager> logger, APIInvoker invoker)
{
_logger = logger;
_invoker= invoker;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
List<Task<object>> tasks = new List<Task<object>>();
tasks.Add(_invoker.GetImportWarningsAsync("1"));
tasks.Add(_invoker.GetImportErrorsAsync("2"));
tasks.Add(_invoker.GetImportStatusAsync("3"));
}
其中GetImportWarningsAsync
、GetImportErrorsAsync
、GetImportStatusAsync
定义为:
internal async Task<string> GetImportWarningsAsync(...)
internal async Task<string> GetImportErrorsAsync(...)
internal async Task<ImportResponse> GetImportLeadStatusAsync(...)
如果它们 return 不同类型,我是否可以做 tasks.Add(...)
我不清楚,我正在将它们添加到 List<Task<object>>
。我不认为这是可能的。我怎样才能实现这样的目标?
最终,我想 运行 在 tasks
中的每个 Task
中的任何一个执行时都使用一个方法。
例如
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
List<Task<object>> tasks = new List<Task<object>>();
tasks.Add(_invoker.GetImportWarningsAsync("1"));
tasks.Add(_invoker.GetImportErrorsAsync("2"));
tasks.Add(_invoker.GetImportStatusAsync("3"));
Task<object> finishedTask = await Task.WhenAny(tasks);
tasks.Remove(finishedTask);
HandleTask(finishedTask, await finishedTask);
}
private void HandleTask(Task task, object value)
{
if (value is ImportResponse)
{
_logger.LogInformation((value as ImportResponse).someProp); // Log something
}
else
{
// Any other object type will be logged here - In this case string.
_logger.LogInformation(value.ToString());
}
}
任务不像那样协变,但没有什么能阻止您根据需要自行转换结果:
var tasks = new List<Task<object>>();
tasks.Add(((Func<Task<object>>)(async () => (object)await _invoker.GetImportWarningsAsync("1")))());
tasks.Add(((Func<Task<object>>)(async () => (object)await _invoker.GetImportErrorsAsync("2")))());
tasks.Add(((Func<Task<object>>)(async () => (object)await _invoker.GetImportStatusAsync("3")))());
这很可能不是最好的方法,但它确实按预期工作。
public static class TaskExtensions
{
public static async Task<(T1, T2)> WhenAll<T1, T2>(Task<T1> t1, Task<T2> t2)
{
return (await t1, await t2);
}
public static async Task<(T1, T2, T3)> WhenAll<T1, T2, T3>(Task<T1> t1, Task<T2> t2, Task<T3> t3)
{
return (await t1, await t2, await t3);
}
public static async Task<(T1, T2, T3, T4)> WhenAll<T1, T2, T3, T4>(Task<T1> t1, Task<T2> t2, Task<T3> t3, Task<T4> t4)
{
return (await t1, await t2, await t3, await t4);
}
//etc.
}
这里我们利用了ValueTuple
.
用法示例:
var (warnings, errors, status) = await TaskExtensions.WhenAll(
_invoker.GetImportWarningsAsync("1"),
_invoker.GetImportErrorsAsync("2"),
_invoker.GetImportStatusAsync("3")
);
这里我们利用了 C# 7 的解构功能。
解构变量的类型:
warnings
: string
errors
: string
status
: ImportResponse
如果你经常这样做,你可以使用如下所示的扩展方法ToObjectAsync
:
public static async Task<object> ToObjectAsync<T>(this Task<T> task)
{
return await task;
}
用法示例:
var tasks = new List<Task<object>>();
tasks.Add(_invoker.GetImportWarningsAsync("1").ToObjectAsync());
tasks.Add(_invoker.GetImportErrorsAsync("2").ToObjectAsync());
tasks.Add(_invoker.GetImportStatusAsync("3").ToObjectAsync());
本质上等同于Blindy的,只是更方便一些。
我有一个 .NET Core 2.1 项目,它有一个 BackgroundService
,我希望它的职责只是处理记录来自一组不同任务的结果,这些任务可以 return 不同的值。我想将他们的所有输出分组到任务管理器 class 中以记录他们的输出。是否有可能有一个 List<Task>
将包含来自这些异步方法的所有 Task
对象?
我不想为每个要 await
的方法设置多个 Task
字段。我宁愿将它们放入某种 List
中,因为可能会有比我希望此管理器管理的这三种异步方法更多的方法。
我正在考虑做类似的事情:
public class MyTaskManager : BackgroundService
{
private readonly ILogger<MyTaskManager> _logger;
private APIInvoker _invoker;
public MyTaskManager (ILogger<MyTaskManager> logger, APIInvoker invoker)
{
_logger = logger;
_invoker= invoker;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
List<Task<object>> tasks = new List<Task<object>>();
tasks.Add(_invoker.GetImportWarningsAsync("1"));
tasks.Add(_invoker.GetImportErrorsAsync("2"));
tasks.Add(_invoker.GetImportStatusAsync("3"));
}
其中GetImportWarningsAsync
、GetImportErrorsAsync
、GetImportStatusAsync
定义为:
internal async Task<string> GetImportWarningsAsync(...)
internal async Task<string> GetImportErrorsAsync(...)
internal async Task<ImportResponse> GetImportLeadStatusAsync(...)
如果它们 return 不同类型,我是否可以做 tasks.Add(...)
我不清楚,我正在将它们添加到 List<Task<object>>
。我不认为这是可能的。我怎样才能实现这样的目标?
最终,我想 运行 在 tasks
中的每个 Task
中的任何一个执行时都使用一个方法。
例如
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
List<Task<object>> tasks = new List<Task<object>>();
tasks.Add(_invoker.GetImportWarningsAsync("1"));
tasks.Add(_invoker.GetImportErrorsAsync("2"));
tasks.Add(_invoker.GetImportStatusAsync("3"));
Task<object> finishedTask = await Task.WhenAny(tasks);
tasks.Remove(finishedTask);
HandleTask(finishedTask, await finishedTask);
}
private void HandleTask(Task task, object value)
{
if (value is ImportResponse)
{
_logger.LogInformation((value as ImportResponse).someProp); // Log something
}
else
{
// Any other object type will be logged here - In this case string.
_logger.LogInformation(value.ToString());
}
}
任务不像那样协变,但没有什么能阻止您根据需要自行转换结果:
var tasks = new List<Task<object>>();
tasks.Add(((Func<Task<object>>)(async () => (object)await _invoker.GetImportWarningsAsync("1")))());
tasks.Add(((Func<Task<object>>)(async () => (object)await _invoker.GetImportErrorsAsync("2")))());
tasks.Add(((Func<Task<object>>)(async () => (object)await _invoker.GetImportStatusAsync("3")))());
这很可能不是最好的方法,但它确实按预期工作。
public static class TaskExtensions
{
public static async Task<(T1, T2)> WhenAll<T1, T2>(Task<T1> t1, Task<T2> t2)
{
return (await t1, await t2);
}
public static async Task<(T1, T2, T3)> WhenAll<T1, T2, T3>(Task<T1> t1, Task<T2> t2, Task<T3> t3)
{
return (await t1, await t2, await t3);
}
public static async Task<(T1, T2, T3, T4)> WhenAll<T1, T2, T3, T4>(Task<T1> t1, Task<T2> t2, Task<T3> t3, Task<T4> t4)
{
return (await t1, await t2, await t3, await t4);
}
//etc.
}
这里我们利用了ValueTuple
.
用法示例:
var (warnings, errors, status) = await TaskExtensions.WhenAll(
_invoker.GetImportWarningsAsync("1"),
_invoker.GetImportErrorsAsync("2"),
_invoker.GetImportStatusAsync("3")
);
这里我们利用了 C# 7 的解构功能。
解构变量的类型:
warnings
:string
errors
:string
status
:ImportResponse
如果你经常这样做,你可以使用如下所示的扩展方法ToObjectAsync
:
public static async Task<object> ToObjectAsync<T>(this Task<T> task)
{
return await task;
}
用法示例:
var tasks = new List<Task<object>>();
tasks.Add(_invoker.GetImportWarningsAsync("1").ToObjectAsync());
tasks.Add(_invoker.GetImportErrorsAsync("2").ToObjectAsync());
tasks.Add(_invoker.GetImportStatusAsync("3").ToObjectAsync());
本质上等同于Blindy的