C# 异步 Foreach
Posted
技术标签:
【中文标题】C# 异步 Foreach【英文标题】:C# Async 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(() => KeepUpdatingEverything...
StartTimer 方法在做什么?
@TheodorZoulias 启动计时器以每 5 秒运行一次 KeepUpdatingEverything。我检查了这篇文章,但将其更改为 Task 类型并没有任何区别。我将在主帖中编辑完整的 StartTimer 代码
“它一直跳过我要运行的任务,并且不再更新它。”
你知道await GetStockPrices(ticker)
是否抛出异常?在这种情况下,我的期望是异常会升级为应用程序崩溃。除非存在一些额外的错误吞噬代码(空 catch
块),否则您已从问题中省略。
【参考方案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);
【讨论】:
试过了,但遗憾的是似乎也没有什么不同以上是关于C# 异步 Foreach的主要内容,如果未能解决你的问题,请参考以下文章