gpt4 book ai didi

c# - 为什么文件异步API会阻塞

转载 作者:行者123 更新时间:2023-11-30 13:09:08 27 4
gpt4 key购买 nike

我正在编写一个简单的Metro应用。但是,API在访问文件时会阻塞。通过阻塞,我的意思是程序永远等待。创建/打开文件或文件夹最多需要几秒钟。在这种情况下,它需要永远。

当我运行程序时,它永远不会从OnTest回来。是你得到的。
我了解.Wait将等待文件和文件夹的创建完成。也许这不是一个好的设计。但是,这不是重点。

我的问题是:


您是否得到相同的行为(永远阻止该程序)
这是应该发生的事情还是WinRT中的错误? (我正在使用消费者预览)
如果这是预期的行为,那么为什么要永远这样做呢?


这是XAML代码:

<Button Click="OnTest">Test</Button>


这是C#代码:

 private async void OnTest(object sender, RoutedEventArgs e)
{
var t = new Cache("test1");
t = new Cache("test2");
t = new Cache("test3");
}
class Cache
{
public Cache(string name)
{
TestRetrieve(name).Wait();
}
public static async Task TestRetrieve(string name)
{
StorageFolder rootFolder = ApplicationData.Current.LocalFolder;
var _folder = await rootFolder.CreateFolderAsync(name, CreationCollisionOption.OpenIfExists);
var file = await _folder.CreateFileAsync("test.xml", CreationCollisionOption.OpenIfExists);
}
}


它在第二次调用new Cache(“ test2”)时阻塞;

最佳答案

我没有尝试运行您的程序或重现您的问题,但是我可以对正在发生的事情做出有根据的猜测。

假设您为自己编写了以下任务清单:


在信箱里给妈妈写一封信。
阅读我的回复后,立即设置闹钟将我唤醒。
去睡觉。
检查邮箱以获取回复。
阅读回复。


现在严格按照从上到下的顺序执行该列表中的所有操作。怎么了?

问题不在于邮局或妈妈。他们正在拿起您放入邮箱的信,然后寄给妈妈,妈妈给她写回信,而邮局则把它寄回给您。问题是您永远都不会进入第四步,因为您只能在完成第五步后才能开始第四步,并且闹钟将您唤醒。您将永远睡觉,因为您本质上是在等待未来的自我唤醒您现在的自我。


  埃里克,谢谢你的解释。


别客气。


  但是,对于为什么我的代码不起作用,我仍然感到困惑。


好,让我们分解一下。您的程序实际上是做什么的?让我们简化一下:

void M()
{
Task tx = GetATask();
tx.Wait();
}
async Task GetATask()
{
Task ty = DoFileSystemThingAsync();
await ty;
DoSomethingElse();
}


首先,什么是任务?任务是一个对象,它表示(1)要完成的工作,以及(2)任务继续的委托:任务完成后需要发生的事情。

因此,您调用GetATask。它有什么作用?好吧,它要做的第一件事就是制作一个Task并将其存储在ty中。该任务表示作业“在磁盘上启动某些操作,并在完成时通知I / O完成线程”。

该任务的延续是什么?完成该任务后会发生什么?需要调用DoSomethingElse。因此,编译器将等待转换为一堆代码,这些代码告诉任务确保在完成任务时调用DoSomethingElse。

一旦设置了I / O任务的继续,则方法GetATask将任务返回给调用者。那是什么任务这与存储在ty中的任务不同。返回的任务是代表该任务的任务,它执行GetATask方法需要执行的所有操作。

该任务的延续是什么?我们不知道!这取决于GetATask的调用者来决定。

好的,让我们回顾一下。我们有两个任务对象。一个代表任务“在文件系统上执行此操作”。文件系统完成工作后即可完成。它的延续是“调用DoSomething”。我们有第二个任务对象,代表任务“在GetATask主体中执行所有操作”。将在对DoSomethingElse的调用返回后完成。

再次:当文件I / O成功时,第一个任务将完成。发生这种情况时,文件I / O完成线程将向主线程发送一条消息,说“嘿,您正在等待的文件I / O已经完成。我告诉您这是因为现在是时候调用DoSomethingElse ”。

但是主线程没有检查其消息队列。为什么不?因为您告诉它同步等待直到GetATask中的所有内容(包括DoSomethingElse)完成。但是现在无法处理告诉您运行DoSomethingElse的消息,因为您正在等待DoSomethingElse完成。

现在清楚了吗?您正在告诉线程等待线程完成DoSomethingElse的运行,然后再检查“请调用DoSomethingElse”是否在该线程上要执行的工作队列中!您正在等待,直到您读完妈妈的来信,但实际上您正在同步等待,这意味着您不检查邮箱是否已收到这封信。

在这种情况下,调用Wait显然是错误的,因为您正在等待自己将来做某事,而这行不通。但是更普遍的是,首先调用Wait会完全否定异步的全部要点。只是不要那样做。说“我想异步”和“但我想同步等待”都没有任何意义。那些是相反的。

关于c# - 为什么文件异步API会阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10114555/

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