无法从“System.Threading.Tasks.Task”转换为“System.Collections.Gener

本文关键字:System 转换 Gener Collections Tasks Threading Task | 更新日期: 2023-09-27 18:35:11

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

我有一个列表中每个 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);
        }
    }

无法从“System.Threading.Tasks.Task”转换为“System.Collections.Gener

如果您已经在使用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.Delay并在其上await

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

编辑 2:

你的代码不起作用的原因是startDownload async void,而你没有等待它。因此,无论您Task.Delay如何,您的while循环都会不断迭代。

由于你位于控制台应用程序内部,因此无法await Main因为方法不能异步。因此,要解决此问题,请将startDownload更改为async Task而不是async void,并Wait返回的Task。请注意,几乎永远不应该使用Wait,对于特殊情况(例如在控制台应用中运行时的情况),预期:

public async Task StartDownload()

然后

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

另请注意,混合Parallel.Foreachasync-await并不总是最好的主意。您可以在 Nesting await in Parallel.ForEach 中阅读更多相关信息

你会看到 ContinueWith 将 AS 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>,其中TResult将是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)));
相关文章: