【问题标题】:C# Async ForeachC# 异步 Foreach
【发布时间】:2022-01-12 13:45:00
【问题描述】:

我正忙于在 Windows 窗体中开发一个股票跟踪器应用程序以备不时之需。为了优化我的代码,我决定重写使所有内容保持最新的 main 函数。我认为选择正确的行并从那里工作会更容易,而不是为正确的控件搜索所有控件。问题是:它不断跳过我要运行的任务,并且不再更新它。我已经尝试了很多我在互联网上找到的东西,但我无法让它工作。所以我恢复到最简单的原始代码形式,看看你们是否有想法。以下是这一切的精髓:

        public async void KeepUpdatingEverything(List<object> positionInfo, List<string> tickerList)
        {
            foreach (string ticker in tickerList)
            {
                //code that gets the right row
                List<object> priceInfo = await GetStockPrices(ticker));
                //code that updates all the labels
            }
        }

这个想法是,当调用 KeepUpdating 函数时,它会检查带有代码的列表,获取每个代码的价格并随后更新所有相关标签。但我似乎无法让它工作,因为它一直跳过异步调用。有什么想法吗?

在输入第一个代码时,会调用一次 KeepUpdatingEverything,之后它只会不断更新代码列表。

        private async void button1_Click(object sender, EventArgs e)
        {
            string ticker;
            using (Prompt prompt = new Prompt("Enter the ticker symbol", "Add ticker"))
            {
                ticker = prompt.Result;
                ticker = ticker.ToUpper();
                if (!string.IsNullOrEmpty(ticker))
                {

                    using (Prompt prompt2 = new Prompt("Enter your volume", "Add ticker"))
                    {
                        if (Int32.TryParse(prompt2.Result, out int volume) == true)
                        {
                            using (Prompt prompt3 = new Prompt("Enter your buy price", "Add ticker"))
                            {
                                if (Double.TryParse(prompt3.Result, out double buyPrice) == true)
                                {
                                    try
                                    {
                                        List<object> priceInfo = await GetStockPrices(ticker);
                                        FillTickerLabel(ticker);

                                        List<object> positionInfo = GetPositionVars(ticker, volume, buyPrice, Convert.ToDouble(priceInfo[1]));
                                        FillPositionLabel(ticker, priceInfo[0].ToString(), positionInfo);

                                        List<object> changeInfo = GetChangeVars(ticker, priceInfo);
                                        FillChangeLabels(ticker, priceInfo[0].ToString(), changeInfo);

                                        List<string> tickerList = new List<string>();
                                        tickerList.Add(ticker);
                                        if (tickerList.Count <= 1)
                                        {
                                            _cancellationToken = new CancellationTokenSource();
                                            _runningTask = StartTimer(() => KeepUpdatingEverything(positionInfo, tickerList), _cancellationToken);

                                        }
                                    }
                                    catch
                                    {
                                        MessageBox.Show("Ticker does not exist, or entered incorrect value somewhere else");
                                    }
                                }
                                else
                                {
                                    MessageBox.Show("You did not enter one of the textboxes correctly");
                                }
                            }
                        }
                        else
                        {
                            MessageBox.Show("You did not enter one of the textboxes correctly");
                        }
                    }
                }
                else
                {
                    MessageBox.Show("You did not enter one of the textboxes correctly");
                }
            }
        }

最后是StartTimer函数:

        private async Task StartTimer(Action action, CancellationTokenSource cancellationTokenSource)
        {
            try
            {
                while (!cancellationTokenSource.IsCancellationRequested)
                {
                    await Task.Delay(5000, cancellationTokenSource.Token);
                    action();
                }
            }
            catch (OperationCanceledException) { }
        }

【问题讨论】:

  • KeepUpdatingEverything 方法在哪里/如何被调用?你也知道这篇文章吗? Avoid async void.
  • _runningTask = StartTimer(() =&gt; KeepUpdatingEverything... StartTimer 方法在做什么?
  • @TheodorZoulias 启动计时器以每 5 秒运行一次 KeepUpdatingEverything。我检查了这篇文章,但将其更改为 Task 类型并没有任何区别。我将在主帖中编辑完整的 StartTimer 代码
  • “它一直跳过我要运行的任务,并且不再更新它。”
  • 你知道await GetStockPrices(ticker)是否抛出异常?在这种情况下,我的期望是异常会升级为应用程序崩溃。除非存在一些额外的错误吞噬代码(空 catch 块),否则您已从问题中省略。

标签: c# winforms asynchronous foreach stock


【解决方案1】:

async void 表示你不返回调用者可以await 的任务。

你应该像这样使用async Task

public async Task KeepUpdatingEverything(List<object> positionInfo, List<string> tickerList)

【讨论】:

  • 嗯,我试过了,但似乎没有什么不同。它仍然取消执行任务。
【解决方案2】:

更新汉斯的答案。 你需要await父方法中的调用。

await KeepUpdatingEverything(...)

它会一直等到完成。

顺便说一句,在 foreach 中 await 并不是最好的方法。 将所有任务结果放入列表或数组中并await它们会更容易。

await Tasks.WhenAll(tasks);

【讨论】:

  • 试过了,但遗憾的是似乎也没有什么不同
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-10
  • 2012-10-15
  • 2012-06-16
  • 1970-01-01
  • 2016-11-27
相关资源
最近更新 更多