0

我试图了解 iocp 和 io 完成线程池。据我所知,IO 像 http 请求一样通过 iocp 和 io 完成线程来执行回调代码。但我发现文件读取、Http 请求和 SQL 查询之间存在一些差异。

class Program
{
    static void Main(string[] args)
    {
        FileAsync().Wait();
        PrintSeparate();
        SqlAsync().Wait();
        PrintSeparate();
        HttpAsync().Wait();
        Console.ReadKey();
    }

    private static async Task FileAsync()
    {
        PrintThreads($"{nameof(FileAsync)}-Entry             ");
        var buffer = new byte[1024];
        using (var file = new FileStream(@"D:\a.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous))
        {
            PrintThreads($"{nameof(FileAsync)}-AfterNewFileStream");
            await file.ReadAsync(buffer, 0, 1024);
            PrintThreads($"{nameof(FileAsync)}-AfterReadAsync    ");
            PrintFirstStack();
        }
    }

    private static async Task HttpAsync()
    {
        PrintThreads($"{nameof(HttpAsync)}-Entry         ");
        var httpClient = new HttpClient();
        var response = await httpClient.GetAsync(@"https://stackoverflow.com");
        PrintThreads($"{nameof(HttpAsync)}-AfterGetAsync ");
        PrintFirstStack();
        await response.Content.ReadAsStringAsync();
        PrintThreads($"{nameof(HttpAsync)}-AfterReadAsync");
        PrintFirstStack();
    }

    private static async Task SqlAsync()
    {
        PrintThreads($"{nameof(SqlAsync)}-Entry            ");
        using (var connection = new SqlConnection("Data Source=***;Initial Catalog=t;User ID=sa; Password=***"))
        using (var command = new SqlCommand("select count(1) from aa", connection))
        {
            PrintThreads($"{nameof(SqlAsync)}-AfterNewConCmd   ");
            await connection.OpenAsync();
            PrintThreads($"{nameof(SqlAsync)}-AfterOpenAsync   ");
            PrintFirstStack();
            var o = await command.ExecuteScalarAsync();
            PrintThreads($"{nameof(SqlAsync)}-AfterExecuteAsync");
            PrintFirstStack();
        }
    }

    private static void PrintThreads(object flag)
    {
        ThreadPool.GetAvailableThreads(out var workThreads, out var ioThreads);
        PrintThreads(flag, workThreads, ioThreads);
    }

    private static void PrintThreads(object flag, int workThreads, int ioThreads)
    {
        Console.WriteLine($"[{flag}] {nameof(workThreads)}: {workThreads}, {nameof(ioThreads)}: {ioThreads}");
    }

    private static void PrintSeparate()
    {
        Console.WriteLine("\n-------------------------------------------------------------------------------\n");
    }

    private static void PrintFirstStack()
    {
        Console.WriteLine(Environment.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Last());
    }
}

输出:

[FileAsync-Entry             ] workThreads: 2047, ioThreads: 1000
[FileAsync-AfterNewFileStream] workThreads: 2047, ioThreads: 999
[FileAsync-AfterReadAsync    ] workThreads: 2046, ioThreads: 1000
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

-------------------------------------------------------------------------------

[SqlAsync-Entry            ] workThreads: 2047, ioThreads: 1000
[SqlAsync-AfterNewConCmd   ] workThreads: 2047, ioThreads: 1000
[SqlAsync-AfterOpenAsync   ] workThreads: 2046, ioThreads: 1000
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
[SqlAsync-AfterExecuteAsync] workThreads: 2045, ioThreads: 1000
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

-------------------------------------------------------------------------------

[HttpAsync-Entry         ] workThreads: 2047, ioThreads: 1000
[HttpAsync-AfterGetAsync ] workThreads: 2047, ioThreads: 999
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
[HttpAsync-AfterReadAsync] workThreads: 2047, ioThreads: 999
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

输出显示,只有 http 请求使用 ioThread 执行回调,为什么?文件和sql使用ioThread insdie框架代码,然后将用户代码回调入队到workthreadpool?

而且我测试了很多次,new FileStream(..)总是拿一个ioThread,这是怎么回事?

4

0 回答 0