找回密码
 立即注册
搜索
查看: 2575|回复: 22

[其他] c# 求助,TCP服务器性能问题

[复制链接]
头像被屏蔽
     
发表于 2021-7-15 14:53 | 显示全部楼层 |阅读模式
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

     
发表于 2021-7-15 15:21 | 显示全部楼层
NetworkStream.Read()不是non-blocking的,socket没数据的时候NetworkStream.Read()不会立刻return 0,而是一直block住到timeout
用NetworkStream.DataAvailable 做判断条件

有问题先看文档
https://docs.microsoft.com/en-us ... Int32_System_Int32_
回复

使用道具 举报

头像被屏蔽
     
发表于 2021-7-15 15:22 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

头像被屏蔽
     
 楼主| 发表于 2021-7-15 15:26 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

头像被屏蔽
     
 楼主| 发表于 2021-7-15 15:30 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

头像被屏蔽
     
发表于 2021-7-15 15:31 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

头像被屏蔽
     
发表于 2021-7-15 15:49 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

     
发表于 2021-7-15 16:27 | 显示全部楼层
本帖最后由 Damenly 于 2021-7-15 16:30 编辑

buffer是在内存里的,几十个客户端也不会吃内存,所以应该不是磁盘的问题。 固定下每个client发的数据大小看看?非csharp程序员,还有如果真如楼上所说这个read是blocking有一定timeout了,我都怀疑是不是这个read 是不是busy waiting,文档一句没写

回复

使用道具 举报

     
发表于 2021-7-15 16:33 | 显示全部楼层
前面没注意到你就是要block

你用的是Task.Run(),它不一定会开新线程,很有可能你好几个客户端连接的task是在同一个线程里处理的。
一个task在Read这里block了,是否会马上切换到下一个task,我不清楚
回复

使用道具 举报

     
发表于 2021-7-15 23:30 | 显示全部楼层
本帖最后由 hourousha 于 2021-7-15 23:32 编辑

没记错的话.net core里l的异步tcp在linux中是用epoll实现的,其他怎么实现不清楚。也许实现的有问题,还是建议是用async,可以和System.IO.Pipelines并用提升性能。
至于LS说的多个客户端任务在一个线程里执行,我认为可能性不大。因为毕竟这些task func中并没有await在中途释放当前线程,那么其他的task func自然也没有道理在此func完成前占用该线程。
回复

使用道具 举报

     
发表于 2021-7-16 00:16 来自手机 | 显示全部楼层
hourousha 发表于 2021-7-15 23:30
没记错的话.net core里l的异步tcp在linux中是用epoll实现的,其他怎么实现不清楚。也许实现的有问题,还是 ...

我觉得Task有问题的可能性还是比较大啊

这个Task内部的方法是阻塞的,而且执行时间很长
Task的背后是线程池,同时执行的数量是有上限的,系统自动控制
这里应该设置成Long running,具体有什么用我倒是忘了

其实这边我建议用Thread手动控制线程,既然想要一一对应
Task内部有很多东西是看不出来的

— from Xiaomi MIX 2S, Android 10 of S1 Next Goose v2.4.4.1
回复

使用道具 举报

     
发表于 2021-7-16 00:28 | 显示全部楼层
感觉是到线程池数量上限了,前面的task都block住了,线程让不出来,新的task都queue住了

回复

使用道具 举报

头像被屏蔽
     
 楼主| 发表于 2021-7-16 00:56 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

头像被屏蔽
     
 楼主| 发表于 2021-7-16 01:05 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

头像被屏蔽
     
发表于 2021-7-16 10:01 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

     
发表于 2021-7-16 10:20 | 显示全部楼层
长运行为什么不用 线程 wait awake 的机制?
回复

使用道具 举报

     
发表于 2021-7-16 14:33 | 显示全部楼层
EraserKing 发表于 2021-7-16 00:16
我觉得Task有问题的可能性还是比较大啊

这个Task内部的方法是阻塞的,而且执行时间很长

线程池耗尽的问题,可以某种意义上用LongRunning的TaskCreateOption来解决。
但这本身并不是解决这个(多并发TCP)的问题的根本办法。以我的观点来看,对于高并发的IO操作,使用线程+blocking IO基本接近于原则错误。因为它和其底层的实现,无论是linux下的epoll还是windows下的IOCP,思路都是背道而驰的,对性能基本只有负面影响。
所以要不就是用XXXXAsync+Task,要不就是用BeginXXXX/EndXXXX
回复

使用道具 举报

     
发表于 2021-7-16 17:43 来自手机 | 显示全部楼层
hourousha 发表于 2021-7-16 14:33
线程池耗尽的问题,可以某种意义上用LongRunning的TaskCreateOption来解决。
但这本身并不是解决这个(多 ...

我只是说Task的问题
他这么写和网络没关系,只要是有大量Task就会遇到

— from Xiaomi MIX 2S, Android 10 of S1 Next Goose v2.4.4.1
回复

使用道具 举报

     
发表于 2021-7-16 20:24 | 显示全部楼层
为啥不异步呢
回复

使用道具 举报

头像被屏蔽
     
 楼主| 发表于 2021-7-16 20:57 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

     
发表于 2021-7-16 23:40 | 显示全部楼层
sdefrfg 发表于 2021-7-16 20:57
因为异步用的不熟练
而且本来就是几个小时写好拿来验证几个分布式算法的,并没有要测高并发需求, ...

改异步其实没多少改动量的,简单来说就是用XXXXAsync代替XXXX,比如将原Read方法改成如下即可
  1. async Task Read(TcpClient connection, CancellationToken token)
  2. {
  3.      NetworkStream stream = connection.GetStream();
  4.      Byte[] buffer = new Byte[1024];
  5.      while(true){
  6.          try{
  7.              int size = await stream.ReadAsync(buffer, 0, buffer.Length, token);
  8.              if(size <=0){
  9.                  break;
  10.              }
  11.              //...干其他事情
  12.          }
  13.          catch{
  14.              break;
  15.          }
  16.      }
  17.      stream.Dispose();
  18.      connection.Dispose();
复制代码
如果有socket数据解析要求(根据定义的数据包头尾规则解析分离出数据包),建议用System.IO.Pipelines.Pipe,它实现了一个高效的数据队列(先进先出)容器,有一个写入接口PipeWriter和一个读取接口PipeReader,它的作用类似于java第三方库netty里的bytebuf。用法简单来说就是TCP读取的Task不断调用PipeWriter.GetMemory(int sizehint)获取内存并用NetworkStream.ReadAsync(Memory<byte>,..) 和PipeWriter.Advance(int writesize)往Pipe里写数据,然后再建一个Task通过不断PipeReader.ReadAsync读取数据,处理得到的数据并通过PipeReader.AdvanceTo()来设置数据处理指针与数据检查指针,这样可以方便处理一次报文中含多数据包,或者一个数据包需要多次报文接收才完整的情况。同时这样也将网络接收与数据处理给并行了起来,可以提高网络吞吐。
基本来说,.net core本身在TCP这方面就比较完善了,所以不像java在这方面对诸如netty等第三方库有很高的需求。

回复

使用道具 举报

     
发表于 2021-7-16 23:46 来自手机 | 显示全部楼层
IO不异步,天理难容…
回复

使用道具 举报

头像被屏蔽
     
 楼主| 发表于 2021-7-16 23:56 来自手机 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|上海互联网违法和不良信息举报中心|网上有害信息举报专区|962110 反电信诈骗|举报电话 021-62035905|Stage1st ( 沪ICP备13020230号-1|沪公网安备 31010702007642号 )

GMT+8, 2024-9-24 01:14 , Processed in 0.127668 second(s), 6 queries , Gzip On, Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表