c# 4.5 - 一个主要做数据库插入的 TCP 服务器是否应该在一个任务上启动每个客户端
c# 4.5 - Should a TCP Server, mainly doing database inserts, start each client on a Task
我的理解是 async await 用于 IO(网络、数据库等),并行任务用于 cpu。
注意:这段代码为了简洁起见有点苛刻post。
我有一个用 c# 创建的 windows 服务,它具有以下代码
while (true)
{
var socket = await tcpListener.AcceptSocketAsync();
if (socket == null) { break; }
var client = new RemoteClient(socket);
Task.Run(() => client.ProcessMessage());
}
在 RemoteClient 中 class ProcessMessage 方法执行此操作
byte[] buffer = new byte[4096];
rawMessage = string.Empty;
while (true)
{
Array.Clear(buffer, 0, buffer.Length);
int bytesRead = await networkStream.ReadAsync(buffer, 0, buffer.Length);
rawMessage += (System.Text.Encoding.ASCII.GetString(buffer).Replace("[=11=]", string.Empty));
if (bytesRead == 0 || buffer[buffer.Length - 1] == 0)
{
StoreMessage();
return;
}
}
所以我的 I/O 工作是异步进行的。但我的顾虑和问题是使用 Task.Run 来开始工作 我还在创建一个块吗?
我正在尝试建立一个 TCP 连接并尽快释放它,以便扩展到大量连接。
我觉得我在这里混合范式。
谢谢
My understanding is that async await is for IO (network, db, etc) and parallel task is for cpu.
我会说理解不正确。 async
/await
用于任何异步操作,无论是 I/O 还是 CPU 绑定。
…my concern and my question is in using Task.Run to kick off the work am I still creating a block?
"A block"?您认为否则会创建什么样的块?
就个人而言,我不会那样写代码。 accept
操作已经在线程池线程中完成(或在同一线程中同步完成),即来自 IOCP 线程池的线程。为该线程上的连接设置一些初始条件,然后从那里启动 I/O 是非常好的。没有理由在另一个线程上排队工作。
所以我写代码的方式是这样的:
async Task ProcessMessage()
{
byte[] buffer = new byte[4096];
rawMessage = string.Empty;
while (true)
{
Array.Clear(buffer, 0, buffer.Length);
int bytesRead = await networkStream.ReadAsync(buffer, 0, buffer.Length);
rawMessage += (System.Text.Encoding.ASCII.GetString(buffer).Replace("[=10=]", string.Empty));
if (bytesRead == 0 || buffer[buffer.Length - 1] == 0)
{
StoreMessage();
return;
}
}
}
那么在您的服务中:
while (true)
{
var socket = await tcpListener.AcceptSocketAsync();
if (socket == null) { break; }
var client = new RemoteClient(socket);
var _ = client.ProcessMessage();
}
备注:
- 虚拟
_
变量只是为了防止编译器警告您有关被忽略的、未等待的异步 return)
- 由于您忽略了 returned
Task
对象,因此您不会收到抛出的异常。因此,您应该为 ProcessMessage()
方法本身添加适当的异常处理。
- 我同意评论者 shr 关于清理的意见。您没有提供完整的代码示例,所以我们不知道例如
StoreMessage()
方法可以。但是 presumably/hopefully 你在某个地方有逻辑可以正确而优雅地关闭连接并关闭套接字。
我的理解是 async await 用于 IO(网络、数据库等),并行任务用于 cpu。
注意:这段代码为了简洁起见有点苛刻post。
我有一个用 c# 创建的 windows 服务,它具有以下代码
while (true)
{
var socket = await tcpListener.AcceptSocketAsync();
if (socket == null) { break; }
var client = new RemoteClient(socket);
Task.Run(() => client.ProcessMessage());
}
在 RemoteClient 中 class ProcessMessage 方法执行此操作
byte[] buffer = new byte[4096];
rawMessage = string.Empty;
while (true)
{
Array.Clear(buffer, 0, buffer.Length);
int bytesRead = await networkStream.ReadAsync(buffer, 0, buffer.Length);
rawMessage += (System.Text.Encoding.ASCII.GetString(buffer).Replace("[=11=]", string.Empty));
if (bytesRead == 0 || buffer[buffer.Length - 1] == 0)
{
StoreMessage();
return;
}
}
所以我的 I/O 工作是异步进行的。但我的顾虑和问题是使用 Task.Run 来开始工作 我还在创建一个块吗?
我正在尝试建立一个 TCP 连接并尽快释放它,以便扩展到大量连接。
我觉得我在这里混合范式。
谢谢
My understanding is that async await is for IO (network, db, etc) and parallel task is for cpu.
我会说理解不正确。 async
/await
用于任何异步操作,无论是 I/O 还是 CPU 绑定。
…my concern and my question is in using Task.Run to kick off the work am I still creating a block?
"A block"?您认为否则会创建什么样的块?
就个人而言,我不会那样写代码。 accept
操作已经在线程池线程中完成(或在同一线程中同步完成),即来自 IOCP 线程池的线程。为该线程上的连接设置一些初始条件,然后从那里启动 I/O 是非常好的。没有理由在另一个线程上排队工作。
所以我写代码的方式是这样的:
async Task ProcessMessage()
{
byte[] buffer = new byte[4096];
rawMessage = string.Empty;
while (true)
{
Array.Clear(buffer, 0, buffer.Length);
int bytesRead = await networkStream.ReadAsync(buffer, 0, buffer.Length);
rawMessage += (System.Text.Encoding.ASCII.GetString(buffer).Replace("[=10=]", string.Empty));
if (bytesRead == 0 || buffer[buffer.Length - 1] == 0)
{
StoreMessage();
return;
}
}
}
那么在您的服务中:
while (true)
{
var socket = await tcpListener.AcceptSocketAsync();
if (socket == null) { break; }
var client = new RemoteClient(socket);
var _ = client.ProcessMessage();
}
备注:
- 虚拟
_
变量只是为了防止编译器警告您有关被忽略的、未等待的异步 return) - 由于您忽略了 returned
Task
对象,因此您不会收到抛出的异常。因此,您应该为ProcessMessage()
方法本身添加适当的异常处理。 - 我同意评论者 shr 关于清理的意见。您没有提供完整的代码示例,所以我们不知道例如
StoreMessage()
方法可以。但是 presumably/hopefully 你在某个地方有逻辑可以正确而优雅地关闭连接并关闭套接字。