【发布时间】:2017-02-08 14:49:21
【问题描述】:
通过所有异步/等待(来自线程池),我遇到了一个有趣的挑战。
我有一个在 WPF 应用程序中运行的 TCP 服务器,它接受客户端并将它们存储在 List<> 中,如下所示:
private List<Client> clients = new List<Client>();
while (running && clientCount <= maxClients)
{
Client client = new Client(await server.AcceptTcpClientAsync());
await client.WriteLineAsync("Connected to the Server!");
clients.Add(client);
clientCount++;
}
所以我想做的是遍历我的客户列表,如果收到任何数据,我想将其附加到文本框。我意识到这可能不是实现这一目标的最佳方式,我愿意接受建议,但这是我目前的结构。
一个按钮启动循环并不断调用并等待AllReadLineAsync()
private async void btnStartReadLoopClick(object sender, RoutedEventArgs e)
{
btnStartReadLoop.IsEnabled = false;
while(server.clientCount > 0)
{
string text = await server.AllReadLineAsync();
txtOutputLog.AppendText("[client] " + text + "\n");
}
}
这是什么功能:
public async Task<string> AllReadLineAsync()
{
var tasklist = new List<Task<string>>();
foreach (var client in clients)
tasklist.Add(client.ReadLineAsync());
while (tasklist.Count > 0)
{
Task<string> finishedTask = await Task.WhenAny(tasklist);
if (finishedTask.Status == TaskStatus.RanToCompletion)
return await finishedTask;
tasklist.Remove(finishedTask);
}
return "Error: No task finished";
}
此函数遍历客户端列表并创建所有ReadLineAsync() 任务的List<Tast<string>>。
在任何给定时间,我可能只有 1 或 2 个客户端实际发送数据,所以我不能 WhenAll() 并且我尝试了 WhenAny() 和 WaitAny() 没有成功。
未来的 Google 员工注意事项:WaitAny() 与 Wait() 类似,并且处于阻塞状态。不要在 UI 线程上执行此操作。而是使用 WhenAny() 并等待它。
所以我目前的实现是可行的,但我无法弄清楚如果其他客户端不发送数据,消息将从 1 个客户端建立的这个错误。
TL;DR:我是否正确使用了WhenAny(),还是有更好的方法让我等待 ReadLineAsync 并将结果传递给文本框?
编辑:这是我看到的行为 我按以下顺序输入:左、右、左 2、右 2、左 3、右 3 似乎有些消息正在被丢弃?
编辑2:我在MSDN博客上找到了我复制的代码sn-p的来源:https://blogs.msdn.microsoft.com/pfxteam/2012/08/02/processing-tasks-as-they-complete/
此代码 sn-p 专门用于遍历任务列表以确保它们全部完成。我不在乎任务是否重复,所以我需要修改代码以始终检查整个任务列表,而不是删除任何任务。
【问题讨论】:
-
您没有删除运行完成的任务..?
-
天哪,因为 return 语句绕过了 remove 语句......哇。让我试一试。
-
@stuartd 好吧,这并没有修复问题,但它确实告诉我,有时 2 个或更多 ReadLineAsync 被组合在一起。但是,似乎某些消息从一个客户端延迟到另一个客户端发送消息。
-
我认为这可能是因为
tasklist可以减少到只有 1 个任务,此时它的功能就好像它只是在等待那个任务
标签: c# wpf asynchronous task-parallel-library