Apo*_*ehn 1 sockets performance benchmarking tcp pipe
这个问题类似于IPC性能:命名管道与套接字,但重点关注匿名而不是命名管道:不同操作系统和不同传输大小的匿名管道和TCP连接之间的性能差异如何?
我尝试使用BenchmarkDotNet对其进行基准测试,代码附在本文末尾。当程序启动时,它会初始化 BenchmarkDotNet,而 BenchmarkDotNet 会调用这些方法一次,并多次调用GlobalSetup()两个基准测试方法(Pipe()和)。Tcp()
在 中GlobalSetup(),启动了两个子进程。一种用于管道通信,一种用于 TCP 通信。N一旦子进程准备就绪,它们就会等待触发信号和要传输的值的数量(通过提供stdin),然后开始发送数据。
当调用基准方法(Pipe()和Tcp())时,它们发送触发信号和值的数量N并等待传入数据。
它表明,设置TcpClient.NoDelay = true禁用 Nagle 算法非常重要,该算法首先收集小消息,直到达到某个阈值或某个超时。有趣的是,这仅影响 Linux 测试N = 10000。使用NoDelay = false(默认),此测试的平均时间从~40 \xc2\xb5s跳到~40 ms。
结果如下:
\n传奇
\n虚拟机(Ubuntu 20.04)
\nBenchmarkDotNet=v0.13.0, OS=ubuntu 20.04\nAMD Opteron(tm) Processor 4334, 4 CPU, 4 logical and 4 physical cores\n.NET SDK=5.0.102\n [Host] : .NET 5.0.2 (5.0.220.61120), X64 RyuJIT\n DefaultJob : .NET 5.0.2 (5.0.220.61120), X64 RyuJIT\nRun Code Online (Sandbox Code Playgroud)\n| 方法 | 氮 | 意思是 | 错误 | 标准差 | 中位数 | 比率 | 比率SD |
|---|---|---|---|---|---|---|---|
| 管道 | 1 | 27.33 \xce\xbcs | 1.660 \xce\xbcs | 第4.895章 | 30.75 \xce\xbcs | 1.00 | 0.00 |
| TCP | 1 | 31.42 \xce\xbcs | 0.620 \xce\xbcs | 0.713 \xce\xbcs | 31.24 \xce\xbcs | 1.39 | 0.21 |
| 管道 | 100 | 26.72 \xce\xbcs | 1.990 \xce\xbcs | 第5.867章 | 26.63 \xce\xbcs | 1.00 | 0.00 |
| TCP | 100 | 38.95 \xce\xbcs | 2.146 \xce\xbcs | 第6.327章 | 43.34 \xce\xbcs | 1.53 | 0.43 |
| 管道 | 10000 | 42.45 \xce\xbcs | 第2.804章 | 第8.268章 | 47.09 \xce\xbcs | 1.00 | 0.00 |
| TCP | 10000 | 46.97 \xce\xbcs | 第3.057章 | 9.013 \xce\xbcs | 53.93\xce\xbcs | 1.16 | 0.34 |
| 管道 | 1000000 | 1,621.87 \xce\xbcs | 116.924\xce\xbcs | 344.752\xce\xbcs | 1,893.49 \xce\xbcs | 1.00 | 0.00 |
| TCP | 1000000 | 1,707.25 \xce\xbcs | 8.066\xce\xbcs | 第7.545章 | 1,707.24 \xce\xbcs | 0.94 | 0.13 |
| 管道 | 10000000 | 21,013.86 \xce\xbcs | 166.250\xce\xbcs | 129.797 \xce\xbcs | 21,007.89 \xce\xbcs | 1.00 | 0.00 |
| TCP | 10000000 | 20,548.03 \xce\xbcs | 407.779\xce\xbcs | 814.379\xce\xbcs | 20,713.44 \xce\xbcs | 0.96 | 0.03 |
笔记本(Windows 10 + WSL2 上的 Ubuntu 20.04):
\nBenchmarkDotNet=v0.13.0, OS=ubuntu 20.04\nIntel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores\n.NET SDK=5.0.301\n [Host] : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT\n DefaultJob : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT\nRun Code Online (Sandbox Code Playgroud)\n| 方法 | 氮 | 意思是 | 错误 | 标准差 | 中位数 | 比率 | 比率SD |
|---|---|---|---|---|---|---|---|
| 管道 | 1 | 44.66 \xce\xbcs | 0.882 \xce\xbcs | 1.051 \xce\xbcs | 44.45 \xce\xbcs | 1.00 | 0.00 |
| TCP | 1 | 54.42\xce\xbcs | 0.411 \xce\xbcs | 0.364 \xce\xbcs | 54.34 \xce\xbcs | 1.21 | 0.03 |
| 管道 | 100 | 45.07 \xce\xbcs | 0.895 \xce\xbcs | 1.496 \xce\xbcs | 44.63 \xce\xbcs | 1.00 | 0.00 |
| TCP | 100 | 55.27\xce\xbcs | 0.735 \xce\xbcs | 0.614 \xce\xbcs | 55.17\xce\xbcs | 1.21 | 0.05 |
| 管道 | 10000 | 52.30\xce\xbcs | 1.018 \xce\xbcs | 1.131 \xce\xbcs | 52.32\xce\xbcs | 1.00 | 0.00 |
| TCP | 10000 | 55.47\xce\xbcs | 0.590 \xce\xbcs | 0.523 \xce\xbcs | 55.32\xce\xbcs | 1.06 | 0.03 |
| 管道 | 1000000 | 4,034.01 \xce\xbcs | 77.978\xce\xbcs | 65.115 \xce\xbcs | 4,035.58 \xce\xbcs | 1.00 | 0.00 |
| TCP | 1000000 | 1,398.62 \xce\xbcs | 24.230 \xce\xbcs | 21.479 \xce\xbcs | 1,395.20 \xce\xbcs | 0.35 | 0.01 |
| 管道 | 10000000 | 69,767.35 \xce\xbcs | 4,993.492 \xce\xbcs | 14,723.423 \xce\xbcs | 64,169.46\xce\xbcs | 1.00 | 0.00 |
| TCP | 10000000 | 24,660.43 \xce\xbcs | 1,746.809 \xce\xbcs | 4,955.406 \xce\xbcs | 23,947.15 \xce\xbcs | 0.38 | 0.14 |
笔记本电脑(Windows 10):
\nBenchmarkDotNet=v0.13.0, OS=Windows 10.0.19043.1083 (21H1/May2021Update)\nIntel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores\n.NET SDK=5.0.203\n [Host] : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT\n DefaultJob : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT\nRun Code Online (Sandbox Code Playgroud)\n| 方法 | 氮 | 意思是 | 错误 | 标准差 | 中位数 | 比率 | 比率SD |
|---|---|---|---|---|---|---|---|
| 管道 | 1 | 22.60 \xce\xbcs | 0.441 \xce\xbcs | 1.013 \xce\xbcs | 22.21 \xce\xbcs | 1.00 | 0.00 |
| TCP | 1 | 27.42 \xce\xbcs | 0.535 \xce\xbcs | 1.019 \xce\xbcs | 27.51 \xce\xbcs | 1.21 | 0.08 |
| 管道 | 100 | 21.93 \xce\xbcs | 0.146 \xce\xbcs | 0.122 \xce\xbcs | 21.94 \xce\xbcs | 1.00 | 0.00 |
| TCP | 100 | 26.06 \xce\xbcs | 0.506 \xce\xbcs | 0.474 \xce\xbcs | 25.99 \xce\xbcs | 1.19 | 0.02 |
| 管道 | 10000 | 29.59 \xce\xbcs | 0.126 \xce\xbcs | 0.099 \xce\xbcs | 29.58 \xce\xbcs | 1.00 | 0.00 |
| TCP | 10000 | 33.25 \xce\xbcs | 0.655 \xce\xbcs | 0.919 \xce\xbcs | 33.01 \xce\xbcs | 1.14 | 0.04 |
| 管道 | 1000000 | 1,675.35 \xce\xbcs | 32.862\xce\xbcs | 43.870\xce\xbcs | 1,685.37 \xce\xbcs | 1.00 | 0.00 |
| TCP | 1000000 | 2,553.07 \xce\xbcs | 58.100 \xce\xbcs | 167.631 \xce\xbcs | 2,505.34 \xce\xbcs | 1.63 | 0.10 |
| 管道 | 10000000 | 23,421.61 \xce\xbcs | 141.337 \xce\xbcs | 132.207\xce\xbcs | 23,380.19 \xce\xbcs | 1.00 | 0.00 |
| TCP | 10000000 | 28,182.91 \xce\xbcs | 375.644\xce\xbcs | 313.679\xce\xbcs | 28,114.22\xce\xbcs | 1.20 | 0.01 |
基准代码:
\n基准.csproj
\n<Project Sdk="Microsoft.NET.Sdk">\n\n <PropertyGroup>\n <OutputType>Exe</OutputType>\n <TargetFramework>net5.0</TargetFramework>\n </PropertyGroup>\n\n <ItemGroup>\n <PackageReference Include="BenchmarkDotNet" Version="0.13.0" />\n </ItemGroup>\n\n</Project>\nRun Code Online (Sandbox Code Playgroud)\n程序.cs
\n\nusing BenchmarkDotNet.Running;\nusing System;\nusing System.IO;\nusing System.Linq;\nusing System.Net.Sockets;\nusing System.Runtime.InteropServices;\n\nnamespace Benchmark\n{\n public class Program\n {\n public const int MIN_LENGTH = 1;\n public const int MAX_LENGTH = 10_000_000;\n\n static void Main(string[] args)\n {\n if (!args.Any())\n {\n var summary = BenchmarkRunner.Run<PipeVsTcp>();\n }\n else\n {\n var data = MemoryMarshal\n .AsBytes<int>(\n Enumerable\n .Range(0, MAX_LENGTH)\n .ToArray())\n .ToArray();\n\n using var readStream = Console.OpenStandardInput();\n\n if (args[0] == "pipe")\n {\n using var pipeStream = Console.OpenStandardOutput();\n RunChildProcess(readStream, pipeStream, data);\n }\n\n else if (args[0] == "tcp")\n {\n var tcpClient = new TcpClient()\n {\n NoDelay = true\n