繁体   English   中英

无法从“ System.Threading.Tasks.Task”转换为“ System.Collections.Generic.Dictionary” <string,string> &#39;

[英]Cannot convert from 'System.Threading.Tasks.Task' to 'System.Collections.Generic.Dictionary<string,string>'

我相信我可能只是语法错误,但是我想做的是创建一个在另一个任务完成后运行的任务。

我对列表中的100个数组有一个任务。 它启动一个新线程,将该数组传递给方法。 该方法完成后将返回字典。 我正在尝试创建一个方法完成后要运行的任务,该任务将返回的字典传递给执行更多工作的单独方法。

static void Main(string[] args)
    {
        try
        {
            stopwatch = new Stopwatch();
            stopwatch.Start();
            while (true)
            {
                startDownload();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

public static async void startDownload()
    {
        try
        {

            DateTime currentDay = DateTime.Now;

            if (Helper.holidays.Contains(currentDay) == false)
            {
                List<string> markets = new List<string>() { "amex", "global", "nasdaq", "nyse" };

                Parallel.ForEach(markets, async market =>
                {
                    try
                    {

                        IEnumerable<string> symbolList = Helper.getStockSymbols(market);
                        var historicalGroups = symbolList.Select((x, i) => new { x, i })
                          .GroupBy(x => x.i / 100)
                          .Select(g => g.Select(x => x.x).ToArray());

                        Task<Dictionary<string, string>>[] historicalTasks =
                                                           historicalGroups.Select(x => Task.Run(() =>
                                                           Downloads.getHistoricalStockData(x, market)))
                                                                    .ToArray();

                        Dictionary<string, string>[] historcalStockResults = await
                                                                             Task.WhenAll(historicalTasks);

                        foreach (var dictionary in historcalStockResults)
                        {
                            Downloads.updateSymbolsInDB(dictionary);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                });

                await Task.Delay(TimeSpan.FromHours(24));
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

如果您已经在使用await我建议不要使用ContinueWith 原因是您最终在代码中出现的冗长。

相反,请尽可能使用await 代码最终如下所示:

var historicalGroups = symbolList
                       .Select((x, i) => new { x, i })
                       .GroupBy(x => x.i / 100)
                       .Select(g => g.Select(x => x.x).ToArray());

var historicalTasks = historicalGroups.Select(x => Task.Run(() => 
                                       Downloads.getHistoricalStockData(x, market)))
                                      .ToArray();

var historcalStockResults = await Task.WhenAll(historicalTasks);

foreach (var dictionary in historcalStockResults)
{
    Downloads.updateSymbolsInDB(dictionary);
}

注意使用Task.Run代替Task.Factory.StartNew 您应该改用它。 这里更多

编辑:

如果您需要每24小时执行一次此代码,请添加Task.Delayawait它:

await Task.Delay(TimeSpan.FromHours(24));

编辑2:

您的代码无法正常工作的原因是因为startDownloadasync void ,并且您没有等待它。 因此while无论您的Task.Delay如何,您的while循环都会保持迭代。

因为您在控制台应用程序内部,所以无法await因为Main方法不能异步。 因此,要解决此问题, startDownload更改为async Task而不是async void ,然后Wait返回的Task 请注意, 几乎不应该使用Wait ,除非有特殊情况(例如在控制台应用程序中运行时):

public async Task StartDownload()

接着

while (true)
{
    StartDownload().Wait();
}

还要注意,混合Parallel.Foreachasync-await并非总是最好的主意。 您可以在Parallel.ForEach中的嵌套等待中了解更多信息。

您会看到ContinueWith将Task作为参数。

此外,通过仔细阅读我们注释中的逻辑,您似乎需要更新代码。 您试图对所有WhenAll任务的结果运行一次Downloads.updateSymbolsInDB 就您而言,您似乎需要

await Task<Dictionary<string, string>>
    .WhenAll(historicalGroups.Select(g => Task.Factory.StartNew(() => Downloads.getHistoricalStockData(g, market))))
    .ContinueWith((i) => Downloads.updateSymbolsInDB(i.Result.Aggregate((agg, next) =>
            {
                foreach (var p in next)
                {
                    if (!agg.ContainsKey(p.Key)) { agg.Add(p.Key, p.Value); }
                }
                return agg;
            })));

请注意,我还使用Task<TResult>进行初始化,因此对ContinueWith进行了强类型化,以提供Dictionary<string, string> i.Result

另请注意,您将需要重新i.Result.Aggregate逻辑中的操作。 您需要对其进行更新以使其正确无误。 此外,值得回顾一下多次调用Downloads.updateSymbolsInDB是否更有效,或者Aggregate调用是否是更好的选择。

(最后一点:最终结果是void ,因此未分配等待。)

在审查中,您的代码存在许多问题(仅作为陈述,不是指责-并非故意犯罪)。 通过Task.Factory.StartNewWhenAll方法创建的任务没有返回值,因此只是基本的Task对象,实际上正在丢弃Downloads.getHistoricalStockData工作的结果。 然后,您的ContinueWith需要与WhenAllTask<TResult> WhenAll ,其中TResult将是WhenAll中每个任务的返回值的WhenAll

编辑:如被问到如果要多次调用Downloads.updateSymbolsInDB ,如何更新代码,可以简单地通过以下方式完成:

IEnumerable<string> symbolList = Helper.getStockSymbols(market);
var historicalGroups = symbolList.Select((x, i) => new { x, i })
    .GroupBy(x => x.i / 100)
    .Select(g => g.Select(x => x.x).ToArray());
Parallel.ForEach(historicalGroups, g => Downloads.updateSymbolsInDB(Downloads.getHistoricalStockData(g, market)));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM