IPC 性能:匿名管道与套接字

Apo*_*ehn 1 sockets performance benchmarking tcp pipe

这个问题类似于IPC性能:命名管道与套接字,但重点关注匿名而不是命名管道:不同操作系统和不同传输大小的匿名管道和TCP连接之间的性能差异如何?

Apo*_*ehn 5

我尝试使用BenchmarkDotNet对其进行基准测试,代码附在本文末尾。当程序启动时,它会初始化 BenchmarkDotNet,而 BenchmarkDotNet 会调用这些方法一次,并多次调用GlobalSetup()两个基准测试方法(Pipe()和)。Tcp()

\n

在 中GlobalSetup(),启动了两个子进程。一种用于管道通信,一种用于 TCP 通信。N一旦子进程准备就绪,它们就会等待触发信号和要传输的值的数量(通过提供stdin),然后开始发送数据。

\n

当调用基准方法(Pipe()Tcp())时,它们发送触发信号和值的数量N并等待传入​​数据。

\n

它表明,设置TcpClient.NoDelay = true禁用 Nagle 算法非常重要,该算法首先收集小消息,直到达到某个阈值或某个超时。有趣的是,这仅影响 Linux 测试N = 10000。使用NoDelay = false(默认),此测试的平均时间从~40 \xc2\xb5s跳到~40 ms

\n

结果如下:

\n

传奇

\n
    \n
  • N : N = 要传输的 int32 值的数量
  • \n
  • 平均值:所有测量值的算术平均值
  • \n
  • 误差:99.9% 置信区间的一半
  • \n
  • StdDev :所有测量值的标准偏差
  • \n
  • 中位数:分隔所有测量值的上半部分的值(第 50 个百分位)
  • \n
  • 比率:比率分布的平均值([当前]/[基线])
  • \n
  • RatioSD :比率分布的标准偏差([当前]/[基线])
  • \n
  • 1 微秒:1 微秒(0.000001 秒)
  • \n
\n

虚拟机(Ubuntu 20.04)

\n
BenchmarkDotNet=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\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n
方法意思是错误标准差中位数比率比率SD
管道127.33 \xce\xbcs1.660 \xce\xbcs第4.895章30.75 \xce\xbcs1.000.00
TCP131.42 \xce\xbcs0.620 \xce\xbcs0.713 \xce\xbcs31.24 \xce\xbcs1.390.21
管道10026.72 \xce\xbcs1.990 \xce\xbcs第5.867章26.63 \xce\xbcs1.000.00
TCP10038.95 \xce\xbcs2.146 \xce\xbcs第6.327章43.34 \xce\xbcs1.530.43
管道1000042.45 \xce\xbcs第2.804章第8.268章47.09 \xce\xbcs1.000.00
TCP1000046.97 \xce\xbcs第3.057章9.013 \xce\xbcs53.93\xce\xbcs1.160.34
管道10000001,621.87 \xce\xbcs116.924\xce\xbcs344.752\xce\xbcs1,893.49 \xce\xbcs1.000.00
TCP10000001,707.25 \xce\xbcs8.066\xce\xbcs第7.545章1,707.24 \xce\xbcs0.940.13
管道1000000021,013.86 \xce\xbcs166.250\xce\xbcs129.797 \xce\xbcs21,007.89 \xce\xbcs1.000.00
TCP1000000020,548.03 \xce\xbcs407.779\xce\xbcs814.379\xce\xbcs20,713.44 \xce\xbcs0.960.03
\n
\n

笔记本(Windows 10 + WSL2 上的 Ubuntu 20.04):

\n
BenchmarkDotNet=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\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n
方法意思是错误标准差中位数比率比率SD
管道144.66 \xce\xbcs0.882 \xce\xbcs1.051 \xce\xbcs44.45 \xce\xbcs1.000.00
TCP154.42\xce\xbcs0.411 \xce\xbcs0.364 \xce\xbcs54.34 \xce\xbcs1.210.03
管道10045.07 \xce\xbcs0.895 \xce\xbcs1.496 \xce\xbcs44.63 \xce\xbcs1.000.00
TCP10055.27\xce\xbcs0.735 \xce\xbcs0.614 \xce\xbcs55.17\xce\xbcs1.210.05
管道1000052.30\xce\xbcs1.018 \xce\xbcs1.131 \xce\xbcs52.32\xce\xbcs1.000.00
TCP1000055.47\xce\xbcs0.590 \xce\xbcs0.523 \xce\xbcs55.32\xce\xbcs1.060.03
管道10000004,034.01 \xce\xbcs77.978\xce\xbcs65.115 \xce\xbcs4,035.58 \xce\xbcs1.000.00
TCP10000001,398.62 \xce\xbcs24.230 \xce\xbcs21.479 \xce\xbcs1,395.20 \xce\xbcs0.350.01
管道1000000069,767.35 \xce\xbcs4,993.492 \xce\xbcs14,723.423 \xce\xbcs64,169.46\xce\xbcs1.000.00
TCP1000000024,660.43 \xce\xbcs1,746.809 \xce\xbcs4,955.406 \xce\xbcs23,947.15 \xce\xbcs0.380.14
\n
\n

笔记本电脑(Windows 10):

\n
BenchmarkDotNet=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\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n
方法意思是错误标准差中位数比率比率SD
管道122.60 \xce\xbcs0.441 \xce\xbcs1.013 \xce\xbcs22.21 \xce\xbcs1.000.00
TCP127.42 \xce\xbcs0.535 \xce\xbcs1.019 \xce\xbcs27.51 \xce\xbcs1.210.08
管道10021.93 \xce\xbcs0.146 \xce\xbcs0.122 \xce\xbcs21.94 \xce\xbcs1.000.00
TCP10026.06 \xce\xbcs0.506 \xce\xbcs0.474 \xce\xbcs25.99 \xce\xbcs1.190.02
管道1000029.59 \xce\xbcs0.126 \xce\xbcs0.099 \xce\xbcs29.58 \xce\xbcs1.000.00
TCP1000033.25 \xce\xbcs0.655 \xce\xbcs0.919 \xce\xbcs33.01 \xce\xbcs1.140.04
管道10000001,675.35 \xce\xbcs32.862\xce\xbcs43.870\xce\xbcs1,685.37 \xce\xbcs1.000.00
TCP10000002,553.07 \xce\xbcs58.100 \xce\xbcs167.631 \xce\xbcs2,505.34 \xce\xbcs1.630.10
管道1000000023,421.61 \xce\xbcs141.337 \xce\xbcs132.207\xce\xbcs23,380.19 \xce\xbcs1.000.00
TCP1000000028,182.91 \xce\xbcs375.644\xce\xbcs313.679\xce\xbcs28,114.22\xce\xbcs1.200.01
\n
\n

基准代码:

\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>\n
Run Code Online (Sandbox Code Playgroud)\n

程序.cs

\n\n
using 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