簡體   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