gpt4 book ai didi

c# - 递归 WinRT 异步问题

转载 作者:行者123 更新时间:2023-11-30 22:30:39 25 4
gpt4 key购买 nike

我有一些代码可以做这样的事情:

abstract class Data
{
Data(string name, bool load) { if (load) { Load().Wait(); }
abstract Task Load();
}

class XmlData : Data
{
XmlData(string name, bool load = true) : base(name, load) {}
override async Task Load()
{
var file = await GetFileAsync(...);
var xmlDoc = await LoadXmlDocAsync(file);
ProcessXml(xmlDoc);
}
void ProcessXml(XmlDocument xmlDoc)
{
foreach (var element in xmlDoc.Nodes)
{
if (element.NodeName == "something")
new XmlData(element.NodeText);
}
}
}

我似乎(有时)遇到奇怪的计时问题,最终将代码卡在 GetFileAsync(...) 处。这是由调用的递归性质引起的吗?当我将所有 await 调用更改为实际执行 .Wait() 以便它们完成,并基本上摆脱调用的所有异步性质时,我的代码执行得很好。

最佳答案

Is this caused by the recursive nature of the calls? When I change all the await calls to actually do a .Wait() for them to finish, and essentially get rid of all the asynchronous nature of the calls, my code executes fine.

这真的取决于 -

最有可能的罪魁祸首是调用者以某种方式阻塞了用户界面线程(通过调用 Wait() 等)。在这种情况下,await 的默认行为是捕获调用同步上下文,并将结果发回该上下文。

但是,如果调用者正在使用该上下文,您可能会遇到死锁。

这很可能是这种情况,并且是由这行代码引起的:

Data(string name, bool load) { if (load) { Load.Wait(); }

这可以通过让您的库代码(如这个 XmlData 类)显式使用调用同步上下文来轻松避免。这通常仅对用户界面代码是必需的。通过避免捕获,您可以做两件事。首先,您可以提高整体性能(通常是显着提高),其次,您可以避免这种死锁情况。

这可以通过使用 ConfigureAwait 来完成并像这样更改您的代码:

override async Task Load()
{
var file = await GetFileAsync.(...).ConfigureAwait(false);
var xmlDoc = await LoadXmlDocAsync(file).ConfigureAwait(false);
ProcessXml(xmlDoc);
}

话虽这么说 - 我会重新考虑一下这个设计。这里确实有两个问题。

首先,您在构造函数中调用虚方法,这是相当危险的,应尽可能避免,因为它可能导致异常问题。

其次,通过将 this 放入带有 block 的构造函数中,将整个异步操作转变为同步操作。相反,我建议重新考虑这整件事。

也许您可以重新设计它以创建某种形式的工厂,它返回异步加载的数据?这可能就像将用于创建的公共(public) api 设为返回 Task<Data> 的工厂方法一样简单。 ,甚至是通用的 public async Task<TData> Create<TData>(string name) where TData : Data方法,这将允许您保持构造和加载异步并完全避免阻塞。

关于c# - 递归 WinRT 异步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9590404/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com