【问题标题】:How to call an anglesharp async method without AsyncEx library?如何在没有 AsyncEx 库的情况下调用 Anglesharp 异步方法?
【发布时间】:2015-12-19 00:37:48
【问题描述】:

使用AngleSharp,加载 HTML 页面并等待所有样式表下载(如果需要)并且所有脚本都准备好执行解析器,我这样做

    public sealed class WebReader
    {
        private IDocument _ashDocument;

        public async Task Load(string Url)
        {
            var config = Configuration.Default.WithDefaultLoader().WithJavaScript().WithCss();
            var context = BrowsingContext.New(config);
            _ashDocument = await context.OpenAsync(Url);
        }

        public IEnumerable<string> getImage()
        {
            return  _ashDocument.QuerySelectorAll("img").Select(n => n.Attributes["src"].Value);
        }
    }

    static void Main(string[] args)
    {
        WebReader wReader = new WebReader();           
        AsyncContext.Run((Action)(async () =>
        {
            await wReader.Load("http://blogs.msdn.com/b/dotnet/");
        }));
        IEnumerable<string> imageUrls = wReader.getImage();
        foreach (string url in imageUrls)
        {
            Console.WriteLine(url);
        }

        Console.ReadKey();
    }

AsyncContext 是AsyncEx 库的一部分。

没有 AsyncEx 库是否可以做同样的事情?

【问题讨论】:

    标签: c# async-await task-parallel-library task anglesharp


    【解决方案1】:

    没有 AsyncEx 库是否可以做同样的事情?

    不在控制台应用程序内。 AsyncContext 的全部意义在于允许您在 Main 中等待一个方法,它本身不是异步的(也不能是异步的)。唯一的选择是阻止任务。另外,正如@StephanCleary 所指出的,上下文内的延续将在单个线程上恢复,而不是在任意线程池线程上恢复。

    没有它,它只会是:

    static void Main(string[] args)
    {
        WebReader wReader = new WebReader();           
        wReader.Load("http://blogs.msdn.com/b/dotnet/")).Wait();
        IEnumerable<string> imageUrls = wReader.getImage();
        foreach (string url in imageUrls)
        {
            Console.WriteLine(url);
        }
    }
    

    在极少数情况下使用Task.Wait 阻止是可以的,这就是其中之一。

    旁注 - 异步方法应使用 Async 后缀标记,因此您应使用 LoadAsync。此外,.NET 方法命名约定是 Pascal 大小写,而不是驼峰大小写。

    【讨论】:

    • @LeMoussel 是的,是的。请注意,这不是您通常在控制台应用程序以外的任何环境中调用异步方法的方式,这是异常情况。
    • AsyncContextWait 方法之间的主要区别在于AsyncContext 将在单个线程上运行所有延续(默认情况下),而Wait(在控制台应用程序中)将在线程池上运行延续。
    • @StephanCleary 我认为这不是问题。
    【解决方案2】:

    确实可以:

    static void Main(string[] args)
    {
        DoWork();
        Console.ReadKey();
    }
    
    static async void DoWork()
    {
        WebReader wReader = new WebReader();           
        await wReader.Load("http://blogs.msdn.com/b/dotnet/");
        IEnumerable<string> imageUrls = wReader.getImage();
        foreach (string url in imageUrls)
        {
            Console.WriteLine(url);
        }
    }
    

    这将完全一样,唯一的区别是在 DoWork 下载它的数据时正在执行 readkey,如果这个副作用不是不方便那么你很好。

    否则,您可以使用同步事件(ManualResetEvent、AutoResetEvent 等)等到工作完成。

    【讨论】:

    • 为什么需要另一个async void 方法? Load 已经返回了一个 Task,你可以阻止它,完全不需要 Console.ReadKey
    • ReadKey 用于等待用户输入,让程序保持打开状态,直到用户按下某个键。另外,等待任务通常是一个非常糟糕的主意,如果任务与等待调用者在同一个线程上执行,则会造成死锁
    • 如果 OP 需要在操作仍在运行时终止控制台应用程序,那么可以,但我没有看到 OP 在这方面提到任何内容。关于你的第二点,不,它不会陷入僵局。控制台应用程序使用默认的ThreadPoolSynchronizationContext,其中继续在任意线程池线程上安排。这里不会有任何死锁。
    猜你喜欢
    • 2018-03-11
    • 2013-11-16
    • 1970-01-01
    • 1970-01-01
    • 2016-11-23
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    相关资源
    最近更新 更多