为什么我必须使用(异步方法).result而不是await(异步方法)?

时间:2016-10-11 12:33:44

标签: c# multithreading azure asynchronous

我在mediaservices 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);

不等待执行,我的结果是零条目。 我在这里缺少什么?

这是正确的方法吗?

对代码的任何评论都表示赞赏。我不是多线程的国王;)

干杯!

1 个答案:

答案 0 :(得分:4)

请勿跨越新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);
}