前几天对dll进行了修改,解决了多线程冲突的问题。然后将串行真正改成了并行,但是,在实际测试时发现实际延时更高了。

找来找去找不到原因,想不明白为什么。理论上来说,多个网络请求,异步进行多个网络请求应该是比同步阻塞的一个请求一个请求要快很多才对啊。

我对异步的代码和同步的代码执行过程中都用wireshark进行了抓包。但是我发现我缺少一个方法来对抓包得到的数据进行分析。因为这个通讯的过程用的是一个简单的自定义过程。即每次发送过去是一个形如{"idx": 123, "c": "getVel"}的json字符串,收到的是形如{"idx": 123, "r": 12}的json字符串。通过idx字段来标识请求和回答之间的对应关系。每个json字符串都在一个包中,包有五个固定的前缀和四个固定的后缀。包中还有2字节来标识json字符串的长度。

说的有点乱,总之,每个包包括:五个固定前缀+两字节的json字符串长度+json字符串+四个固定后缀。

然而wireshark只能识别一些常用的协议,对于这种自定义的,基于tcp之上的协议,就没啥内置的好的统计办法了。我在网络上查了查,一种办法是自己写lua脚本来作为wireshark的插件。但是我简单看了看放弃了,学不会。。还好我发现了python有个包叫scapy,可以抓包解包,还可以读pcap文件!因此可以用scapy读取wireshark抓的包,然后自己对tcp上的自定义协议进行解析。从而可以得到每个包的时间。

经过统计不同命令的响应时间,每种命令响应时间的分布,发送命令数据包的间隔等统计数据后,发现。。问题不是出在服务器,而是在客户端。

比如如下代码:

            Task add_task = Task.Run(()=>
            {
                int a = random.Next(0, 1000);
                int b = random.Next(1, 1000);
                int r = client.Add(a, b);
            });
            Task sub_task = Task.Run(() =>
            {
                int a = random.Next(0, 1000);
                int b = random.Next(1, 1000);
                int r = client.Sub(a, b);
            });
            Task mul_task = Task.Run(() =>
            {
                int a = random.Next(0, 1000);
                int b = random.Next(1, 1000);
                int r = client.Multiply(a, b);
            });
            Task div_task = Task.Run(() =>
            {
                int a = random.Next(0, 1000);
                int b = random.Next(1, 1000);
                int r = client.Divide(a, b);
            });
            Task.WaitAll(add_task, sub_task, mul_task, div_task);

理想情况下,这四个网络请求应该是间隔很短,几乎一起发送出去才对。

但是从数据来看,mul_task和add_task之间差,很不理想

这个图是延时的散点图,纵坐标单位是ms。可以看到有大量延时非常大的点。不要求你异步之间完全没间隔,但也不能间隔50ms以上吧。。一次网络请求从发送到接受,快的话还不到10ms。结果这个异步任务启动之间间隔就超过了50ms,这就造成了异步还没同步代码快。

延时分布直方图,横坐标单位是ms,纵坐标是数量

从直方图也能看出来。

c#中基于Task的异步,是把每个异步任务交给ThreadPool来执行的。所以对于这个延时这么大的情况,我怀疑可能是由于ThreadPool中线程任务队列比较长,系统中需要ThreadPool执行的任务太多了导致的?这个我后面也没调试了。我有想通过设置ThreadPool.SetMaxThreads来改变ThreadPool中的线程数量,不过通过ThreadPool.GetMaxThreads得到的最大线程数量似乎是16384?如果是这样的话,那可能就不是任务队列的问题,而是处理器调度的问题了。。总之也没进一步调试了。

我在自己的电脑上模仿这个协议写了个服务器,用来计算加减乘除。然后用同步和异步的c#程序分别轮询,用wireshark抓包,再用scapy进行统计,同样发现同步代码的响应时间比异步要快一些,同步代码的平均响应时间是24ms,异步代码的平均响应时间是32ms。不过这个差距不大,而且异步代码虽然响应时间慢一些,但是吞吐量明显比同步要大不少。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注