【问题标题】:Why do I have to use (async method).result instead of await (async method)?为什么我必须使用 (async method).result 而不是 await (async method)?
【发布时间】:2016-10-11 12:33:43
【问题描述】:

我正在媒体服务 Azure 门户中启动 2 个频道。 启动一个频道需要很长时间才能完成,每个频道大约需要 25-30 秒。因此,多线程:)

但是,我不清楚以下内容:

我有两种方法:

public async Task<bool> StartAsync(string programName, CancellationToken token = default(CancellationToken))
    {
        var workerThreads = new List<Thread>();
        var results = new List<bool>();

        foreach (var azureProgram in _accounts.GetPrograms(programName))
        {
            var thread = new Thread(() =>
            {
                var result = StartChannelAsync(azureProgram).Result;
                lock (results)
                {
                    results.Add(result);
                }
            });
            workerThreads.Add(thread);
            thread.Start();
        }

        foreach (var thread in workerThreads)
        {
            thread.Join();
        }

        return results.All(r => r);
    }

private async Task<bool> StartChannelAsync(IProgram azureProgram)
    {
        var state = _channelFactory.ConvertToState(azureProgram.Channel.State);
        if (state == State.Running)
        {
            return true;
        }

        if (state.IsTransitioning())
        {
            return false;
        }

        await azureProgram.Channel.StartAsync();

        return true;
    }

在我使用的第一种方法中

var result = StartChannelAsync(azureProgram).Result;

在这种情况下,一切正常。但是如果我使用

var result = await StartChannelAsync(azureProgram);

不等待执行,我的结果有零条目。 我在这里错过了什么?

这是正确的方法吗?

感谢代码中的任何 cmets。我不是多线程之王;)

干杯!

【问题讨论】:

    标签: c# multithreading azure asynchronous


    【解决方案1】:

    不要跨越新的Thread 实例来并行执行任务,而是使用Task.WhenAll

    public async Task<bool> StartAsync(string programName, CancellationToken token = default(CancellationToken))
    {
        // Create a task for each program and fire them "at the same time"
        Task<bool>[] startingChannels = _accounts.GetPrograms(programName))
                                                            .Select(n => StartChannelAsync(n))
                                                            .ToArray();
    
        // Create a task that will be completed when all the supplied tasks are done
        bool[] results = await Task.WhenAll(startingChannels);
    
        return results.All(r => r);
    }
    

    注意: 我看到您将 CancellationToken 传递给您的 StartAsync 方法,但您实际上并没有使用它。考虑将其作为参数传递给 StartChannelAsync,然后在调用azureProgram.Channel.StartAsync时使用它@


    如果你喜欢单线:

    public async Task<bool> StartAsync(string programName, CancellationToken token = default(CancellationToken))
    {
         return (await Task.WhenAll(_accounts.GetPrograms(programName)
                                             .Select(p => StartChannelAsync(p))
                                             .ToArray())).All(r => r);
    }
    

    【讨论】:

    • 是的,我改变了它。谢谢你!你不应该做 _accounts.GetPrograms(programName)) .Select(n => await StartChannelAsync(n)) .ToArray();注意等待。
    • @MatiasCicero 这不会消除任何并行性。它只会将该方法包装在一个做同样事情的新方法中。这会无缘无故地产生一点开销,所以它唯一能完成的就是稍微减慢代码速度,但它仍然会发挥相同的作用。
    • @Servy 你说得对。我急忙发表评论。
    猜你喜欢
    • 2017-02-28
    • 2020-04-29
    • 2021-03-01
    • 2016-12-03
    • 2017-03-27
    • 2023-03-10
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多