问题描述
使用“异步作用域”生活方式进行注册,但是在活动(异步作用域)作用域的上下文之外请求实例。
- 当我将
return
用于Task
时,会抛出上述错误(大容量时,但处理量较小时,可以) - 但是,当我
await
Task
时,无论吞吐量请求量如何,它都不会起作用。
相对于Simple Injector,我理解这可能是一个更关注异步的问题,但是有何见解为何将return
替换为await
解决了这个问题?
在此先感谢您使用await
进行“工作”是否会隐藏更大的问题。
背景:
我有以下循环,由工作队出队物品(要分派的任务):
void Loop()
{
while (cancellationToken.IsCancellationRequested == false)
{
item = await this.queue.Reader.ReadAsync(cancellationToken);
await dispatchItemAsync(item,(item,dispatcher) =>
{
return dispatcher
.SendAsync(((ISendItem)item).GetHandler,item.Message,item.CancellationToken)
.ContinueWith(t => item.taskcompletionsourceWrapper.SetResult(t.Result),TaskContinuationoptions.runcontinuationsAsynchronously);
});
}
}
上述循环中的dispatchItemAsync
在下面:
protected override async Task dispatchItemAsync(
IQueueItem item,Func<IQueueItem,IThreadStrategy,Task> dispatchFunc)
{
// cast the passed item from channel queue
var queueItemWithStack = item as IQueueItemWithStack;
using (AsyncScopedLifestyle.BeginScope(this.container))
{
var dispatcher = container.GetInstance<InParallel>();
// the above is an interface of delegates that is used to call functions
// return throws SimpleInjector outside of scope exception (intermittent,// always for high request volume)
return dispatchFunc(queueItemWithStack,dispatcher);
// using await no exception is thrown
// await dispatchFunc(queueItemWithStack,dispatcher);
}
}
在InParallel
包含dispatchFunc
行调用的函数的情况下,以下内容(最终通过链)称为:
public Task<object> SendAsync(
Func<SendFunction> getHandler,object request,CancellationToken cancellationToken = default)
{
return this
.inCaller
.SendAsync(getHandler,request,cancellationToken)
.ContinueWith(t =>
{
// snip some code
// the below throws if dispatchItemAsync call us with return
// but is OK if dispatchItemAsync called us with await instead
return t.Result;
});
}
访问ContinueWith
时,上述t.Result
会发生异常:
CommandHandler是使用“异步作用域”生活方式注册的,但是在活动(异步作用域)作用域的上下文之外请求实例。有关如何应用生活方式和管理范围的更多信息,请参见https://simpleinjector.org/scoped。
解决方法
通过不等待Task
,您正在与主操作并行执行Task
。并行意味着代码成为多线程。
这意味着原始Scope
可能会在Task
完成执行之前被处理掉。这会导致您遇到异常。但是在其他情况下,Scope
可能会在执行Task
时被处理掉。 Task
正在运行时,这将导致对象被丢弃。这可能会导致奇怪的多线程问题。
这意味着,根据您的情况,您应该绝对等待Task
返回的dispatchFunc
。