确定网络客户端连接时如何正确排队工作
Determining how to properly queue work when network client connects
我一直在阅读有关 Threadpool.QueueUserWorkItem
(我一直在使用的内容)、Task.Run
和 Task.Factory.StartNew
的信息,但仍然不清楚这里的正确选项是什么。似乎因为我的工作不受 CPU 约束,所以我可能不应该使用 Task.Run
我有自己的线程 运行 等待连接:
Thread listenThread = new Thread(() => ListenForConnection());
listenThread.Name = "lThread";
listenThread.IsBackground = true;
listenThread.Start();
在里面我只是在做:
tlist = new TcpListener(IPAddress.Parse(ip.ToString()), 27275);
tlist.Start();
while (isRunning) {
try {
var client = await tlist.AcceptTcpClientAsync();
ThreadPool.QueueUserWorkItem(HandleClient, client);
}
catch (Exception) { }
}
HandleClient
解析客户端发送的消息,并创建简单 class 的实例或更新现有实例(如果客户端已存在),存储对连接的引用,并更新一些 UI 个元素。
ThreadPool.QueueUserWorkItem
是这里的首选方法还是我偏离了?
编辑:请注意,HandleClient
函数通常需要 5 到 30 毫秒,因此工作量不是很大
我会这样说:
var tcpListener = new TcpListener(IPAddress.Any, 80);
tcpListener.Start();
while (true)
{
var tcpClient = tcpListener.AcceptTcpClient();
Task.Factory.StartNew(() =>
{
// Do whatever you like with your TcpClient
});
}
QueueUserWorkItem
、StartNew
和 Run
或多或少是等价的。我会选择 Task.Run
,因为这是最现代的方式。
你的做法完全没问题。您选择了同步 HandleClient
实现,它强制您在单独的线程上处理连接。请注意,在许多并发连接的情况下,这可能会消耗许多资源。如果您对该场景不感兴趣,这不是问题。否则,这是一个交易破坏者。
如果您使 HandleClient
真正异步和非阻塞,您不需要将该调用推送到线程池。我的建议是仍然这样做,因为它几乎没有缺点,并且可以保护您免受该方法的同步初始部分过长的影响。
catch (Exception) { }
这个我不明白。这可能会隐藏错误。此外,如果接受错误很可能是永久性错误。这种错误处理会将循环变成一个繁忙的循环,消耗一个 CPU 代码的 100%。将 catch 移到循环之外。
我一直在阅读有关 Threadpool.QueueUserWorkItem
(我一直在使用的内容)、Task.Run
和 Task.Factory.StartNew
的信息,但仍然不清楚这里的正确选项是什么。似乎因为我的工作不受 CPU 约束,所以我可能不应该使用 Task.Run
我有自己的线程 运行 等待连接:
Thread listenThread = new Thread(() => ListenForConnection());
listenThread.Name = "lThread";
listenThread.IsBackground = true;
listenThread.Start();
在里面我只是在做:
tlist = new TcpListener(IPAddress.Parse(ip.ToString()), 27275);
tlist.Start();
while (isRunning) {
try {
var client = await tlist.AcceptTcpClientAsync();
ThreadPool.QueueUserWorkItem(HandleClient, client);
}
catch (Exception) { }
}
HandleClient
解析客户端发送的消息,并创建简单 class 的实例或更新现有实例(如果客户端已存在),存储对连接的引用,并更新一些 UI 个元素。
ThreadPool.QueueUserWorkItem
是这里的首选方法还是我偏离了?
编辑:请注意,HandleClient
函数通常需要 5 到 30 毫秒,因此工作量不是很大
我会这样说:
var tcpListener = new TcpListener(IPAddress.Any, 80);
tcpListener.Start();
while (true)
{
var tcpClient = tcpListener.AcceptTcpClient();
Task.Factory.StartNew(() =>
{
// Do whatever you like with your TcpClient
});
}
QueueUserWorkItem
、StartNew
和 Run
或多或少是等价的。我会选择 Task.Run
,因为这是最现代的方式。
你的做法完全没问题。您选择了同步 HandleClient
实现,它强制您在单独的线程上处理连接。请注意,在许多并发连接的情况下,这可能会消耗许多资源。如果您对该场景不感兴趣,这不是问题。否则,这是一个交易破坏者。
如果您使 HandleClient
真正异步和非阻塞,您不需要将该调用推送到线程池。我的建议是仍然这样做,因为它几乎没有缺点,并且可以保护您免受该方法的同步初始部分过长的影响。
catch (Exception) { }
这个我不明白。这可能会隐藏错误。此外,如果接受错误很可能是永久性错误。这种错误处理会将循环变成一个繁忙的循环,消耗一个 CPU 代码的 100%。将 catch 移到循环之外。