はじめに
無料レンタルサーバーを借りて色々遊んでいました。CGI で簡単な API を作っているうちに、サーバー上で C# アプリが動くっぽいことがわかりました。
ただまあ、利用規約的にあれかもしれないので適当な内容にします。
api.cs
Console.WriteLine("Hello .NET!");
Properties/PublishProfiles/FolderProfile.pubxml
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
<OptimizationPreference>Speed</OptimizationPreference>
<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<Http3Support>false</Http3Support>
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
<MetricsSupport>false</MetricsSupport>
<StackTraceSupport>false</StackTraceSupport>
<UseNativeHttpHandler>false</UseNativeHttpHandler>
<XmlResolverIsNetworkingEnabledByDefault>false</XmlResolverIsNetworkingEnabledByDefault>
<IlcOptimizationPreference>Speed</IlcOptimizationPreference>
<InvariantGlobalization>true</InvariantGlobalization>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
<DebuggerSupport>false</DebuggerSupport>
<RootAllApplicationAssemblies>false</RootAllApplicationAssemblies>
<IlcGenerateCompleteTypeMetadata>false</IlcGenerateCompleteTypeMetadata>
<IlcDisableReflection>true</IlcDisableReflection>
<IlcFoldIdenticalMethodBodies>true</IlcFoldIdenticalMethodBodies>
<StripSymbols>true</StripSymbols>
</PropertyGroup>
</Project>
C# のビルドコマンド
dotnet publish -p:PublishProfile=FolderProfile
api.php
<?php
error_reporting(0);
$method = $_SERVER["REQUEST_METHOD"];
$args = "";
if($method == "GET" || $method == "HEAD" || $method == "DELETE") {
$args = http_build_query($_GET);
} else {
$args = base64_encode(file_get_contents('php://input'));
}
$path = $_SERVER['PATH_INFO'];
$resultCode;
passthru("./api $method $path $args", $resultCode);
if($resultCode === 0) {
http_response_code(200);
} else if ($resultCode === 1) {
http_response_code(400);
} else {
http_response_code(500);
}
GET:my-server/api.php/sample
わかったこと
- C# アプリは単一実行形式でビルドすると動く
- サーバーはたいてい
linux-x64
- サーバーはたいてい
- C# アプリは起動が遅い
- C とか Rust が レスポンス 400ms に対して、C# は 800ms とか
- 起動だけでなく型のロードとかあると更に遅くなる
- JIT の関係で起動コストは解消が難しい
- サーバーによっては C#/AoT が使えない
- GLIBC のバージョン問題があり、現状(.NET10)のビルドオプションでは解決できないっぽい
- AoT でもバイナリサイズが 9MB(DB 関係の型を含む)と比較的大きい
- Rust だと 3MB くらい
- Lambda 的な使い方をするなら他の言語でよし
- C、C++、Rust、Go あたりは高速であまり差がない
- 互換性問題にならないようライブラリをうまくトリムするとバイナリが小さくなる
- Aot が使えない限り C# ではこれらに太刀打ちできないよぉ
- C# アプリで DB 接続すると遅い
- レスポンスに 1000ms 以上かかる
- DB 接続コストが高いわけではなく、型ロードにかなり時間がかかる
- 他の言語だと応答 400ms くらい
- サーバーを立ててプロセス間通信で高速化できないか模索
- 少し高速化(応答 1000ms -> 800ms くらいになる)
- 名前付きパイプは応答 200ms くらいかかる
- 共有メモリはアタッチに 70ms くらいかかる、間借りしてるサーバーのメモリを占有しちゃうしんまあ・・・
おわりに
十分実用的なアプリが作れそうな知見が得られたので、何か作ってみようと思います。