.net 完全被异步/等待所迷惑

.net 完全被异步/等待所迷惑,.net,asynchronous,async-await,c#-5.0,.net,Asynchronous,Async Await,C# 5.0,好的,我正在开发一个小的MP3播放器应用程序。它使用数据集保存MP3文件信息。这个问题是关于如何异步加载我的数据集。我读了很多书,尝试了很多东西,但我就是不明白。我所要做的就是采用一个长时间运行的流程数据集填充流程并使其异步 一开始,我有一个数据集(LoadMusic)的方法,如下所示: public partial class dsMusicPlayer { public void LoadMusic() { ... } } public async Task LoadMus

好的,我正在开发一个小的MP3播放器应用程序。它使用数据集保存MP3文件信息。这个问题是关于如何异步加载我的数据集。我读了很多书,尝试了很多东西,但我就是不明白。我所要做的就是采用一个长时间运行的流程数据集填充流程并使其异步

一开始,我有一个数据集(LoadMusic)的方法,如下所示:

public partial class dsMusicPlayer
{
    public void LoadMusic()
    { ... }
}
public async Task LoadMusicAsync()
{
    await Task.Run(() => this.LoadMusicInner());
}

private void LoadMusicInner()
{
    // Work here..
}
它扫描目录结构中的MP3文件,并用文件信息(标题、艺术家、相册等)填充数据集。它可以工作,但需要一分钟左右的时间才能运行,并且自然会阻塞UI。因此,这是异步化的完美候选。我像这样重新编写了加载方法(否则不更改实现):

我知道事情不会那么简单,但我会一步一步来。果然,我得到一个警告,我的异步方法“缺少等待运算符”。我所做的所有阅读都显示在方法调用之前使用了“等待”,因此我将原始方法的主体重构为一个伪私有方法,其唯一目的是允许在容器/公共方法中使用“等待”关键字:

public async void LoadMusicAsync()
{
    await LoadMusicInner();
}

private void LoadMusicInner()
{
}
接下来我看到我不能“等待虚空”,好吧。我将我的私人方法更改为

private Task LoadMusicInner()
{
}

但现在我得到了错误“并非所有代码路径都返回值”——这是有意义的,因为返回类型是Task。这就是我感觉被卡住的地方。我的方法一开始是无效的,因为它实际上不返回任何东西。我应该如何做到这一点?

它应该更像这样:

public partial class dsMusicPlayer
{
    public void LoadMusic()
    { ... }
}
public async Task LoadMusicAsync()
{
    await Task.Run(() => this.LoadMusicInner());
}

private void LoadMusicInner()
{
    // Work here..
}

如果您只想在后台线程上执行一些同步代码,那么在调用代码中,您可以执行以下操作:

await Task.Run(() => player.LoadMusic());
这要求您在调用时将整个方法设置为异步。如果它不是顶级事件处理程序,那么它应该是一个
async Task
方法,它的调用者也应该
等待它,将
async
一直扩展到顶级。然后,顶级事件处理程序应该是
async void
(避免
async void
几乎所有其他地方)


如果您想使代码真正异步(即在执行IO时不阻塞线程),则需要实际更改
LoadMusic()
的实现,方法是将同步调用(如
reader.ReadLine()
)替换为异步版本(如
wait reader.readlinesync()
).

顺便说一句,我最终放弃了一个我理解的老式BackgroundWorker对象,但我的问题仍然存在。有很多关于异步/等待基础知识的文章。我读了一些,但没有真正达到任何目的。谢谢,还没有机会尝试,但到家后会尝试。大多数时候,它不应该是这样。库方法不应使用
Task.Run()
来假装异步。@长度可确定的svick异步任务是
Task.Run的可接受候选任务。启动自己的线程是最终的最佳实践,但自定义调度程序(避免线程池线程)将提供相同的结果。slimmest解决方案是TaskCreationOptions.LongRunning`-它使默认调度程序在设置时避免线程池。