sdefrfg 发表于 2021-7-15 14:53

shinzero 发表于 2021-7-15 15:21

NetworkStream.Read()不是non-blocking的,socket没数据的时候NetworkStream.Read()不会立刻return 0,而是一直block住到timeout
用NetworkStream.DataAvailable 做判断条件

有问题先看文档
https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.networkstream.read?view=net-5.0#System_Net_Sockets_NetworkStream_Read_System_Byte___System_Int32_System_Int32_

abcbuzhiming 发表于 2021-7-15 15:22

sdefrfg 发表于 2021-7-15 15:26

sdefrfg 发表于 2021-7-15 15:30

sblnrrk 发表于 2021-7-15 15:31

abcbuzhiming 发表于 2021-7-15 15:49

Damenly 发表于 2021-7-15 16:27

本帖最后由 Damenly 于 2021-7-15 16:30 编辑

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

shinzero 发表于 2021-7-15 16:33

前面没注意到你就是要block

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

hourousha 发表于 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完成前占用该线程。

EraserKing 发表于 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

shinzero 发表于 2021-7-16 00:28

感觉是到线程池数量上限了,前面的task都block住了,线程让不出来,新的task都queue住了

https://www.cloudsavvyit.com/p/uploads/2020/08/60467b28.png

sdefrfg 发表于 2021-7-16 00:56

sdefrfg 发表于 2021-7-16 01:05

commanderyuri 发表于 2021-7-16 10:01

zxlice 发表于 2021-7-16 10:20

长运行为什么不用 线程 wait awake 的机制?

hourousha 发表于 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

EraserKing 发表于 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

d2loader 发表于 2021-7-16 20:24

为啥不异步呢

sdefrfg 发表于 2021-7-16 20:57

hourousha 发表于 2021-7-16 23:40

sdefrfg 发表于 2021-7-16 20:57
因为异步用的不熟练
而且本来就是几个小时写好拿来验证几个分布式算法的,并没有要测高并发需求, ...
改异步其实没多少改动量的,简单来说就是用XXXXAsync代替XXXX,比如将原Read方法改成如下即可
async Task Read(TcpClient connection, CancellationToken token)
{
   NetworkStream stream = connection.GetStream();
   Byte[] buffer = new Byte;
   while(true){
         try{
             int size = await stream.ReadAsync(buffer, 0, buffer.Length, token);
             if(size <=0){
               break;
             }
             //...干其他事情
         }
         catch{
             break;
         }
   }
   stream.Dispose();
   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等第三方库有很高的需求。

DTCPSS 发表于 2021-7-16 23:46

IO不异步,天理难容…

sdefrfg 发表于 2021-7-16 23:56

页: [1]
查看完整版本: c# 求助,TCP服务器性能问题