编程语言
首页 > 编程语言> > c# – 为什么文件异步API阻塞

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

作者:互联网

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

当我运行程序时,它永远不会从OnTest返回.这是你得到的.
我明白了.等待创建文件和文件夹才能完成.也许那不是很棒的设计.但是,这不是重点.

我的问题是:

>你得到相同的行为(永远阻止程序)
>它应该发生什么,或者它是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);
            }
        }

它阻止第二次调用新的Cache(“test2”);

解决方法:

我没有试图运行你的程序或重现你的问题,但我可以做出有根据的猜测.

假设您自己写了以下待办事项列表:

>在邮箱里给妈妈写一封信.
>设置闹钟,一看到她的回复就叫醒我.
>去睡觉吧.
>检查邮箱是否有回复.
>阅读回复.

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

问题不在于邮局或妈妈;他们拿起你放在邮箱里的信,把它发给妈妈,妈妈正在写她的回复,邮局正把它寄回给你.问题是你永远不会进入第四步,因为你只能在完成第五步后启动第四步并且警报唤醒你.你会永远地睡觉,因为你基本上在等待未来的自我唤醒现在的自我.

Eric, Thank you for the explanation.

别客气.

However, I am still confused as to why my code does not work.

好吧,让我们分解吧.你的计划到底做了什么?让我们简化一下:

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

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

所以你打电话给GetATask.它有什么作用?嗯,它做的第一件事是它制作一个任务并将其存储在ty中.该任务表示作业“在磁盘上启动某些操作,并在完成后通知I / O完成线程”.

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

在设置了I / O任务的延续的那一刻,方法GetATask将一个任务返回给调用者.那是什么任务?这与存储到ty中的任务不同.返回的任务是表示作业执行GetATask方法需要执行的所有操作的任务.

这项任务的延续是什么?我们不知道!这取决于GetATask的调用者.

好的,让我们回顾一下.我们有两个任务对象.一个代表任务“在文件系统上做这件事”.它将在文件系统完成其工作时完成.它的延续是“致电DoSomething”.我们有第二个任务对象代表作业“在GetATask的主体中做所有事情”.它将在调用DoSomethingElse返回后完成.

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

但是主线程没有检查它的消息队列.为什么不?因为你告诉它同步等待GetATask中的所有东西,包括DoSomethingElse,都完成了.但是现在无法处理告诉您运行DoSomethingElse的消息,因为您正在等待DoSomethingElse完成.

现在清楚了吗?你告诉你的线程要等到你的线程完成运行DoSomethingElse,然后再检查“请调用DoSomethingElse”是否在这个线程的工作队列中!你等到你读了妈妈的来信,但是你正在等待同步的事实意味着你没有检查你的邮箱,看看这封信是否已经到达.

在这种情况下,呼叫等待显然是错误的,因为您正在等待自己在将来做某事,而这不会起作用.但更一般地说,调用Wait完全否定了首先出现异步的整个问题.就是不要那样做;同时说“我想要异步”和“但我想同步等待”没有任何意义.那些是对立的.

标签:c,asynchronous,net,microsoft-metro
来源: https://codeday.me/bug/20190711/1436603.html