异步/等待死锁

时间:2018-02-18 15:34:20

标签: c# async-await deadlock

我似乎无法让我的代码工作,尽管我尝试了几种不同的方法。这是我首选的代码段:

var client = await ApiClientProvider.GetApiClient();

        var freeToPlayChampions = await client.GetChampionsAsync(true, Region);

        var championsData = freeToPlayChampions.Select(x =>
            client.GetStaticChampionByIdAsync(
                (int)x.Id,
                platformId: Region));

        ConsoleTable.From(await Task.WhenAll(championsData)).Write();

调试时,我发现代码挂起await Task.WhenAll(championsData)。所以我试着让代码更容易:

 var client = await ApiClientProvider.GetApiClient();

        var freeToPlayChampions = await client.GetChampionsAsync(true, Region);

        var table = new ConsoleTable();
        foreach(var freeToPlayChampion in freeToPlayChampions)
        {
            var championsData = client.GetStaticChampionByIdAsync(
                (int)freeToPlayChampion.Id,
                platformId: Region);

            table.AddRow(await championsData);
        }

        table.Write();

不幸的是,这也会挂起。再次在相同的代码部分,例如await championsData

如何“轻松”使用async / await会导致死锁?在此先感谢您的帮助!

编辑:

以下是全班:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ConsoleTables;
using Mono.Options;
using RiotNet.Models;
using RiotShell.Properties;

namespace RiotShell
{
    public class FreeToPlay : IShellCommand
    {
        public IEnumerable<string> Names { get; }
        public OptionSet Options { get; }

        public bool ShowHelp { get; private set; }
        public string Region { get; private set; }

        public FreeToPlay()
        {
            Names = new List<string>
            {
                "freetoplay",
                "ftp"
            };

            Options = new OptionSet
            {
                { "r|region=" , "The region to execute against", x => Region = x},
                { "h|help|?" , "Show help", x => ShowHelp = true }
            };
        }

        public async Task Execute(IEnumerable<string> args)
        {
            if (ShowHelp)
            {
                Options.WriteOptionDescriptions(Console.Out);
                return;
            }

            if (args.Any())
            {
                throw new Exception(Resources.TooManyArgumentsProvided);
            }

            if (Region == null)
            {
                throw new Exception(string.Format(Resources.RequiredOptionNotFound, "region"));
            }

            if (!PlatformId.All.Contains(Region))
            {
                throw new Exception(string.Format(Resources.InvalidRegion, Region));
            }

            var client = await ApiClientProvider.GetApiClient();

            var freeToPlayChampions = await client.GetChampionsAsync(true, Region);

            var championsData = freeToPlayChampions.Select(x =>
            client.GetStaticChampionByIdAsync(
                (int)x.Id,
                platformId: Region));

            ConsoleTable.From(await Task.WhenAll(championsData)).Write();
        }
    }
}

这是调用者代码,我的主要方法:

    using System;
using System.Threading.Tasks;
using RiotShell.Properties;

namespace RiotShell
{
    public class Program
    {
        public static async Task Main()
        {
            while (true)
            {
                Console.Write(Resources.RiotShellLineString);
                var input = Console.ReadLine();

                try
                {
                    var parsedArgs = InputParser.Parse(input);

                    (var command, var commandArgs) = ArgsToIShellCommandCaster.GetCommand(parsedArgs);

                    await command.Execute(commandArgs);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }         
            }
        }
    }
}

既然希望如此,这里是ApiProvider的代码:

using RiotNet;
using System.Threading.Tasks;

namespace RiotShell
{
    public class ApiClientProvider
    {
        private static IRiotClient _client;

        public static async Task<IRiotClient> GetApiClient()
        {
            if (_client != null)
            {
                _client.Settings.ApiKey = await KeyService.GetKey();
                return _client;
            }

            _client = new RiotClient(new RiotClientSettings
            {
                ApiKey = await KeyService.GetKey()
            });

            return _client;
        }
    }
}

0 个答案:

没有答案