2KB项目,专业的源码交易网站 帮助 收藏 每日签到

可等待的控制台应用 (.NET)

  • 时间:2019-01-23 18:37 编辑:2KB 来源:2KB.COM 阅读:299
  • 扫一扫,手机访问
  • 分享
摘要: 英文原文:Awa
英文原文:Awaitable Console Application

前些天有人贴出了一些代码来让 Async/Await 用起来更简单。他们走的方向是错的,看起来更像是 OnNext/OnError/OnCompleted 的 RXs 模型。错误的原因在于,它并不支持等待。

通常来说,你写的任何 Asyn 代码都会在某个时刻需要同步,所以它必须是可等待的。这就是为什么 async void 是个非常非常狡猾的用法,只应在 event handler 使用,但我们先别提那些了。

我跟写原先那篇文章的小伙子谈话时,指出更典型的用法应该是这样的:

class Program
{
    static void Main(string[] args)
    {

        new Program().Backup();
        Console.ReadLine();
    }


    public async void Backup()
    {
        var backupStatus = await BackupAsync();
    }


    public async TaskBackupAsync()
    {
        return await Task.Run(() => "groovy");
    }

}

另一个犀利的读者指出,你永远不应该用 async void (我这样写是为了尽量跟原作者贴的代码保持一致),而我的代码能正常运行的唯一原因是用了 Console.ReadLine(),阻塞了主线程。

我确实知道我永远不该用 async void ,所以我开始尝试贴出一个改进版本。重要的一点是,我用的是 ConsoleApplication 。所以我尝试这样:

class Program
{
    private  static async void Main(string[] args)
    {
        await new Program().Backup();
    }


    public async Task Backup()
    {
        var backupStatus = await BackupAsync();
        await Task.Delay(5000); //simulate some work
        Console.WriteLine(backupStatus);
    }


    public async TaskBackupAsync()
    {
        return await Task.Run(() => "groovy");
    }
}

编译器发出了抱怨,不允许 async void 的 main 方法。Error 如下:

‘NonAwaitingConsoleApplication.Program.Main(string[])’: an entry point cannot be marked with the ‘async’ modifier

好吧,那改成这样呢?

class Program
{
    private static void Main(string[] args)
    {
        Task.Run(() => MainAsync(args)).Wait();
    }

    static async void MainAsync(string[] args)
    {
        Console.WriteLine(DateTime.Now.ToLongTimeString());
        await new Program().Backup();
        Console.WriteLine(DateTime.Now.ToLongTimeString());
    }

    public async Task Backup()
    {
        var backupStatus = await BackupAsync();
        await Task.Delay(5000); //simulate some work
        Console.WriteLine(backupStatus);
    }


    public async TaskBackupAsync()
    {
        return await Task.Run(() => "groovy");
    }
}

结果它直接闪退了……嗯。有意思。原因在于,在 ConsoleApplication 中没有 SynchronizationContext 。所以线程直接返回到了操作系统,导致程序提前退出。并不是我们想要的结果。怎么办呢?

幸运的是,有一个非常聪明的小伙子 (我高度赞扬) 叫 Stephen Cleary ,他写了一个很棒的 Extension 集,共同参与开发的还有 Stephen Toub (他显然是经验丰富的),所以我充分信任这个库。它叫 NitoAsyncEx 。也可以从 NuGet 获取到它: Nito.AsyncEx

总之,有了这个库,我们就可以写出这样的 AwaitingConsoleApplication 了:

internal class Program
{
    private static void Main(string[] args)
    {
        AsyncContext.Run(() => MainAsync(args));
    }

    static async void MainAsync(string[] args)
    {
        Console.WriteLine(DateTime.Now.ToLongTimeString());
        await new Program().Backup();
        Console.WriteLine(DateTime.Now.ToLongTimeString());
    }

    public async Task Backup()
    {
        var backupStatus = await BackupAsync();
        await Task.Delay(5000); //simulate some work
        Console.WriteLine(backupStatus);
    }


    public async TaskBackupAsync()
    {
        return await Task.Run(() => "groovy");
    }
}

注意其中用到的 AsyncContext ,是神奇的 NitoAsyncEx 类让它成为可能。我强烈建议你看看这个类的内部实现 (可以用 Reflector 看到,或者看 Codeplex 上的 source ),看看它的原理。 Stephen 替你做了很多工作,例如确保存在有效的 SynchronizationContext 。请有空看一看。最好看看整个库,它是个很有用的库。

运行这段代码,输出如下,正是我们想要的;然后就退出了(正常退出)

  • 10:52:21

  • groovy

  • 10:52:26

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。


2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务

  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【计算机/互联网|】Nginx出现502错误(2020-01-20 21:02)
【计算机/互联网|】网站运营全智能软手V0.1版发布(2020-01-20 12:16)
【计算机/互联网|】淘宝这是怎么了?(2020-01-19 19:15)
【行业动态|】谷歌关闭小米智能摄像头,因为窃听器显示了陌生人家中的照片(2020-01-15 09:42)
【行业动态|】据报道谷歌新闻终止了数字杂志,退还主动订阅(2020-01-15 09:39)
【行业动态|】康佳将OLED电视带到美国与LG和索尼竞争(2020-01-15 09:38)
【行业动态|】2020年最佳AV接收机(2020-01-15 09:35)
【行业动态|】2020年最佳流媒体设备:Roku,Apple TV,Firebar,Chromecast等(2020-01-15 09:31)
【行业动态|】CES 2020预览:更多的流媒体服务和订阅即将到来(2020-01-08 21:41)
【行业动态|】从埃隆·马斯克到杰夫·贝佐斯,这30位人物定义了2010年代(2020-01-01 15:14)
联系我们

Q Q: 7090832

电话:400-0011-990

邮箱:7090832@qq.com

时间:9:00-23:00

联系客服
商家入住 服务咨询 投拆建议 联系客服
0577-67068160
手机版

扫一扫进手机版
返回顶部