在使用无限循环时理解火灾并忘记

时间:2017-02-18 02:52:07

标签: c# wpf asynchronous

有人可以告诉我这样做的最佳做法/正确方法是什么? 我也使用WPF,而不是控制台或ASP.NET。

使用Listener接受客户并剥离一个新的"线程"为每个处理该客户端的所有I / O和异常捕获的客户端。

方法1 :点击并忘记,然后将其抛入变量中以消除警告。

parser.parse()

这是客户端处理程序代码:

public static JSONObject convertFileToJSON(String fileName) throws ParseException {
    JSONParser parser = new JSONParser();
    JSONObject jsonObject = null;
    try {
        JSONArray array = (JSONArray) parser.parse(new FileReader(fileName));         
        jsonObject = array.getJsonObject(0);

    } catch (FileNotFoundException e) {

    } catch (IOException ioe) {

    }       
    return jsonObject;
}

方法2 :同样的事情......但是public static async Task Start(CancellationToken token) { m_server = TcpListener.Create(33777); m_server.Start(); running = true; clientCount = 0; // TODO: Add try... catch while (!token.IsCancellationRequested) { var client = await m_server.AcceptTcpClientAsync().ConfigureAwait(false); Client c = new Client(client); var _ = HandleClientAsync(c); } }

public static async Task HandleClientAsync(Client c)
{
    // TODO: add try...catch
    while (c.connected)
    {
        string data = await c.reader.ReadLineAsync();

        // Now we will parse the data and update variables accordingly
        // Just Regex and some parsing that updates variables
        ParseAndUpdate(data);
    }
}

方法3 :中间非异步功能(怀疑这是好的。应该是Async一路)

但这至少摆脱了波浪线,而没有使用那种有点脏的变量技巧。

Task.Run()

方法4 :使HandleClientAsync成为Async void而非Async Task(非常糟糕)

var _ = Task.Run(() => HandleClientAsync());

问题:

  • 使用while (!token.IsCancellationRequested) { var client = await m_server.AcceptTcpClientAsync().ConfigureAwait(false); Client c = new Client(client); NonAsync(c); } public static void NonAsync(VClient vc) { Task.Run(() => HandleClientAsync(vc)); } 做火灾和遗忘任务是否更好?
  • 是否只是接受了你需要使用public static async Task HandleClientAsync(Client c) // Would change to public static async Void HandleClientAsync(Client c) 技巧来解雇并忘记?我可以忽略这个警告,但有些事情是错误的。
  • 如果我想从客户端更新我的UI,我该怎么做?我会使用调度员吗?

谢谢你们

1 个答案:

答案 0 :(得分:0)

我从未成为后期工作者的粉丝,你期望长时间运行,在任务中运行。任务计划在从池中抽取的线程上运行。在安排这些长时间运行的任务时,线程池变得越来越小。最终,池中的所有线程都忙于运行您的任务,事情变得非常缓慢且无法管理。

我的推荐在这里?使用Thread class并自行管理。通过这种方式,您可以保留线程池和完成任务的开销。

附录 - 生产者消费者模型

另一个需要考虑的有趣问题:你真的需要为每个客户提供一个线程吗?在内存开销方面创建和维护线程的成本相当高,如果客户端交互使得客户端线程花费大部分时间等待某些事情要做,那么可能producer consumer模型更多适合您的用例。

示例:

  • 客户端在侦听线程上连接,放入客户端队列
  • 负责检查客户端是否需要任何内容​​的工作线程经常通过该队列进行检查并检查 - 客户端是否有新消息要服务?如果是这样,它为客户端拥有的所有消息提供服务,然后继续

通过这种方式,您可以将工作的线程数限制为管理消息队列所需的数量。您甚至可以根据自所有客户端服务的时间长短以来动态添加工作线程。

如果您坚持

如果你真的喜欢你的目标,我建议你重构一下你所做的事情,而不是HandleClientAsync,你做的更像是类似于CreateServiceForClient(c);

这可能是一个同步方法,它返回类似ClientService的内容。然后,ClientService可以创建执行HandleClientAsync现在所执行操作的任务,并将该任务存储为成员。它还可以提供类似的方法 ClientService.WaitUntilEnd() 和 ClientService.Disconnect()(可以设置取消令牌,也存储为成员变量)