链接 async/await
Chaining async/await
我开发了许多算法,这些算法通过使用常规 Threads
自行完成大部分线程。该方法始终如下
float[] GetData(int requestedItemIndex)
使用上面的方法,索引被推入了一些消息队列,这些消息队列由独立算法的线程处理。所以最后算法的界面是这样的:
public abstract class AlgorithmBase
{
private readonly AlgorithmBase Parent;
private void RequestQueue()
{
}
public float[] GetData(int requestedItemIndex) => Parent.GetData(requestedItemIndex);
}
这个例子很原始,但只是为了获得线索。问题是我可以链接当前适用于我的解决方案的算法。如您所见,每个 GetData 调用父算法的另一个 GetData。这当然会变得更复杂,当然需要有一个最终的父级作为数据源,否则我会得到 WhosebugExceptions。
现在我尝试使用 async/await 来改变这种行为。我的问题是,如果我重写我的代码,我会得到这样的结果:
public abstract class AlgorithmBase
{
private readonly AlgorithmBase Parent;
public async Task<float[]> GetDataAsync(int requestedItemIndex, CancellationToken token = default)
{
var data = await Parent.GetDataAsync(requestedItemIndex);
return await Task.Run<float[]>(async () => ProcessData());
}
}
现在,我已经链接了算法,每个新算法都跨越另一个任务,如果这样做多次,这可能会非常耗时。
所以我的问题是,是否有一种方法可以通过使用定义接口将下一个任务嵌入到已经 运行 的任务中?
不需要明确使用Task.Run
。您应该避免这种情况,并将选择权留给 AlgorithmBase
class 的消费者。
因此,您可以非常类似地实现 async
版本,其中 Task
对象将从父对象传播到子对象:
public abstract class AlgorithmBase
{
private readonly AlgorithmBase Parent;
private void RequestQueue()
{
}
public Task<float[]> GetDataAsync(int requestedItemIndex)
=> Parent.GetDataAsync(requestedItemIndex);
}
最终,一些 "parent" 将以与同步对应物相同的方式实现 GetDataAsync
。
public class SortAlgorithm : AlgorithmBase
{
public override async Task<float[]> GetDataAsync(int requestedItemIndex)
{
// asynchronously get data
var data = await Parent.GetDataAsync(requestedItemIndex);
// synchronously process data and return from asynchronous method
return this.ProcessData(data);
}
private float[] ProcessData(float[] data)
{
}
}
最终,SortAlogirthm
的消费者可以决定是 await
它,还是干脆一劳永逸。
var algo = new SortAlgorithm();
// asynchronously wait until it's finished
var data = await algo.GetDataAsync(1);
// start processing without waiting for the result
algo.GetDataAsync(1);
// not needed - GetDataAsync already returns Task, Task.Run is not needed in this case
Task.Run(() => algo.GetDataAsync(1));
在库代码中等待时,您通常希望在所有 await
上 each and every time, especially if you are awaiting in a loop. So to improve the performance of your library consider using .ConfigureAwait(false)
。
我开发了许多算法,这些算法通过使用常规 Threads
自行完成大部分线程。该方法始终如下
float[] GetData(int requestedItemIndex)
使用上面的方法,索引被推入了一些消息队列,这些消息队列由独立算法的线程处理。所以最后算法的界面是这样的:
public abstract class AlgorithmBase
{
private readonly AlgorithmBase Parent;
private void RequestQueue()
{
}
public float[] GetData(int requestedItemIndex) => Parent.GetData(requestedItemIndex);
}
这个例子很原始,但只是为了获得线索。问题是我可以链接当前适用于我的解决方案的算法。如您所见,每个 GetData 调用父算法的另一个 GetData。这当然会变得更复杂,当然需要有一个最终的父级作为数据源,否则我会得到 WhosebugExceptions。
现在我尝试使用 async/await 来改变这种行为。我的问题是,如果我重写我的代码,我会得到这样的结果:
public abstract class AlgorithmBase
{
private readonly AlgorithmBase Parent;
public async Task<float[]> GetDataAsync(int requestedItemIndex, CancellationToken token = default)
{
var data = await Parent.GetDataAsync(requestedItemIndex);
return await Task.Run<float[]>(async () => ProcessData());
}
}
现在,我已经链接了算法,每个新算法都跨越另一个任务,如果这样做多次,这可能会非常耗时。
所以我的问题是,是否有一种方法可以通过使用定义接口将下一个任务嵌入到已经 运行 的任务中?
不需要明确使用Task.Run
。您应该避免这种情况,并将选择权留给 AlgorithmBase
class 的消费者。
因此,您可以非常类似地实现 async
版本,其中 Task
对象将从父对象传播到子对象:
public abstract class AlgorithmBase
{
private readonly AlgorithmBase Parent;
private void RequestQueue()
{
}
public Task<float[]> GetDataAsync(int requestedItemIndex)
=> Parent.GetDataAsync(requestedItemIndex);
}
最终,一些 "parent" 将以与同步对应物相同的方式实现 GetDataAsync
。
public class SortAlgorithm : AlgorithmBase
{
public override async Task<float[]> GetDataAsync(int requestedItemIndex)
{
// asynchronously get data
var data = await Parent.GetDataAsync(requestedItemIndex);
// synchronously process data and return from asynchronous method
return this.ProcessData(data);
}
private float[] ProcessData(float[] data)
{
}
}
最终,SortAlogirthm
的消费者可以决定是 await
它,还是干脆一劳永逸。
var algo = new SortAlgorithm();
// asynchronously wait until it's finished
var data = await algo.GetDataAsync(1);
// start processing without waiting for the result
algo.GetDataAsync(1);
// not needed - GetDataAsync already returns Task, Task.Run is not needed in this case
Task.Run(() => algo.GetDataAsync(1));
在库代码中等待时,您通常希望在所有 await
上 .ConfigureAwait(false)
。