通过所有异步/等待(来自线程池)的工作,我遇到了一个有趣的挑战。

我有一个在WPF应用程序中运行的TCP Server,该服务器接受客户端并将其存储在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";
}


此函数遍历客户端列表,并创建所有List<Tast<string>>任务的ReadLineAsync()

在任何给定时间,我实际上可能只有1个或2个客户端正在发送数据,因此我不能WhenAll(),并且尝试了WhenAny()WaitAny()都没有成功。

请注意未来的Google员工:WaitAny()就像Wait()一样,并且已被屏蔽。不要在UI线程上执行此操作。而是使用WhenAny()并等待它。

因此,我目前的实现方式是可行的,但我无法弄清楚该错误,即如果其他客户端不发送数据,则消息将从一个客户端建立。

TL; DR:我是否正确使用WhenAny()还是有更好的方法让我等待ReadLineAsync并将结果传递到文本框?

编辑:这是我所看到的行为
我按以下顺序输入:左,右,左2,右2,左3,右3
好像有些邮件被丢弃了吗?

c# - 如何使用Task.WhenAny和ReadLineAsync从任何TcpClient获取数据-LMLPHP

编辑2:我找到了我在MSDN博客上复制的代码段的来源:https://blogs.msdn.microsoft.com/pfxteam/2012/08/02/processing-tasks-as-they-complete/

此代码段专门用于遍历一系列任务,以确保所有任务均已完成。我不在乎任务是否重复,因此我需要修改代码以始终检查整个任务列表,而不是删除任何任务。

最佳答案

好像有些消息被丢弃了吗?


是。因为异步工作是在您调用其方法(例如ReadLineAsync)时启动的。当其中一个完成时(Task.WhenAny),您的代码将放弃其他任务。但是他们继续运行-他们仍在从套接字中读取内容,所读取的内容都将被丢弃。

AFAIK,当您再次从同一套接字开始读取时,行为是不确定的-可能读取下一个内容,或者可能将其排队。我确实知道您不应该同时从套接字(或任何流)发出多次读取。

套接字不是async的理想选择,因为它们可以随时发送数据。您应该改用Rx或事件。可以使async工作,但这非常复杂。

关于c# - 如何使用Task.WhenAny和ReadLineAsync从任何TcpClient获取数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42116277/

10-13 08:37