使用 Async/Await 的 Comet 样式 API 消费

Comet-Style API Consumption with Async/Await

提问人:jokker 提问时间:9/22/2018 最后编辑:abatishchevjokker 更新时间:9/22/2018 访问量:191

问:

我正在尝试从您连接到的 Comet 样式的 HTTP API 中读取数据,它会不断推送事件。我希望它在启动后在后台运行,但我的 Async/Await 是错误的,它冻结了我的 UI,我不知道为什么。

private async void button1_Click(object sender, EventArgs e)
{
    await Task.Run((Func<Task>)PushEventReader);
}

public async Task PushEventReader()
{
    var uri = "url.to/api";
    var client = new WebClient();

    client.OpenReadCompleted += async (sender, e) =>
    {
        using (var reader = new StreamReader(e.Result))
        {
            while (!reader.EndOfStream)
            {
                var line = await reader.ReadLineAsync();
                Console.WriteLine(line);
            }
        }
    };
    await client.OpenReadTaskAsync(new Uri(uri));
}
C# 异步等待 彗星

评论


答:

1赞 Javier Capello 9/22/2018 #1

如果你的按钮点击事件除了在后台启动作业之外什么都没有,那么异步就没有意义了,等待也没有意义,因为在那之后你什么也没做。您可以简单地像这样单击按钮:asyncTask.Run

private void button1_Click(object sender, EventArgs e)
{
    Task.Run(async () => await PushEventReader());
}

Task.Run将您传递给它的任何工作排队以在 ThreadPool 上运行,这将有效地使其在后台运行。

额外:您正在使用的资源是非托管资源(您可以注意到,因为它实现了接口),并且最好在块中使用它们,该块将为您处理处置:WebClientIDisposableusing

public async Task PushEventReader()
{
    var uri = "url.to/api";

    using (var client = new WebClient())
    {
        client.OpenReadCompleted += async (sender, e) =>
        {
            using (var reader = new StreamReader(e.Result))
            {
                while (!reader.EndOfStream)
                {
                    var line = await reader.ReadLineAsync();
                    Console.WriteLine(line);
                }
            }
        };

        await client.OpenReadTaskAsync(new Uri(uri));
    }
}

评论

0赞 Paulo Morgado 9/23/2018
为什么需要?Task.Run
0赞 Javier Capello 9/23/2018
不需要,您可以在没有的情况下完成它,并且它应该以相同的方式工作,我相信它们会编译成完全相同的 IL 代码。但我更喜欢使用,因为在我看来它提高了代码的可读性。Task.RunTask.Run