我遇到了TPL数据流的问题,我似乎无法弄明白。我的代码将在15分钟到几个小时之间运行,直到死锁。我已经做了尽可能多的挖掘,我会尝试在这里发布。
另外,我一般都读到你shouldn't mix asynchronous and blocking code。如果我通过将我的TPL数据流代码隔离到Task.Run(Func<Task<bool>>)
来做错了,请告诉我。否则,我不认为这是问题,因为它在自己的线程上运行。
我的数据流网络设置与this SO link完全相同,请参阅代码。
TransformBlock
涉及许多不同的await
。其中一个函数调用await httpRequest.GetRequestStreamAsync()
。这似乎是发生死锁的地方,因为运行内存分析器会显示四个编译器生成的IAsyncStateMachine
结构卡在内存中(例如<ExampleAsync>d__0
),这些结构都表示在它被调用之前的状态
它还显示110个对象在TransformManyBlock
(以及下一个BatchedJoinBlock
)等待处理,并且只打开了267个HTTP连接(ServicePointManager.DefaultConnectionLimit
已设置到512)。
检查GetRequestStreamAsync
函数的源代码,发现至少有另一个线程是用Task.Run<>()
创建的,这对我来说似乎没用。我以为我甚至可以自己调用FromAsync
函数:
if (...)
{
return Task.Run<Stream>(() => {
TaskFactory<Stream> factory = Task<Stream>.Factory;
WebRequest webRequest = this;
WebRequest webRequest1 = this;
return factory.FromAsync(
new Func<AsyncCallback, object, IAsyncResult> (webRequest.BeginGetRequestStream),
new Func<IAsyncResult, Stream>(webRequest1.EndGetRequestStream),
null
);
});
}
可能是线程池已经用尽了吗?
我唯一的另一个线索是BatchedJoinBlock
可能会占用资源,因为即使每个资源都已完成,它们也永远不会被处理掉 - 这导致我想要继续执行BatchedJoinBlock.Completion
任务一个将在完成后取消联系的人。 (将MaxNumberOfGroups
设置为1似乎没有这样做。)我相信有将近4000个BatchedJoinBlock
徘徊。
我很难过。如果某些内容超时,则会捕获异常并将其传递到Exception
的{{1}}目标。显然,情况并非如此。