使用 async/await + TPL 数据流在远程服务器上执行 SQL select 语句:CPU 或 I/O 绑定?

Executing SQL select statements on a remote server using async/await + TPL dataflow: CPU or I/O bound?

我的 C# WinForms 程序在 Windows 7 客户端计算机上运行,​​并向远程服务器上的 SQL Server 实例提交 SELECT 查询(请参阅数据库下面的代码片段)。我认为我将处理查询结果(一系列 DataTables)的代码归类为 CPU bound 是正确的,但我对如何归类我的数据库代码没有信心(见下文)在客户端机器上运行。一方面,它与 I/O 相关联,但我认为所有使用的 I/O 资源都在远程数据库服务器上并由 SQL 服务器实例处理,而不是 Win 7客户端机器,所以即使我的数据库代码也是 CPU-bound.

我应该 treat/program 我在客户端计算机上运行的数据库代码是 CPU bound 还是 I/O bound?或者,使用 TPL Dataflow 会使这一点变得毫无意义吗?

我的数据库代码

using (SqlConnection sqlConnection = new SqlConnection("Data Source=" + MachineName + ReplaceInstanceName + "; Initial Catalog=" + DbName + "; Integrated Security=True;Connection Timeout=10"))
{
    using (SqlCommand sqlCommand = new SqlCommand())
    {
        sqlCommand.Connection = sqlConnection;
        sqlCommand.CommandType = CommandType.Text;
        sqlCommand.Parameters.AddWithValue("@SearchString", "%" + userProvidedSearchString + "%");
        sqlCommand.CommandText = queryString;

        sqlConnection.Open();
        SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync(ct);
        dataTable_TableDataFromFieldQuery.Load(sqlDataReader);
        sqlConnection.Close();
    }
}

数据存储在数据库服务器的磁盘上,因此大部分 IO 将在那里发生,数据库引擎在这里查询并 returns 将数据发送给调用者(您的应用程序)。连接的两端都会有 CPU 和内存使用,直到您从 SQL 服务器检索到所有批次的数据,此时您将对应用程序内存中的这些行进行操作.

所以你的机器没有受到 IO 攻击;这发生在数据所在的地方。但是,您的代码导致 IO 发生在数据库服务器上,因此请根据您的意愿进行解释。

Should I treat/program my DB code that runs on the client machine as CPU bound or I/O bound

我认为这里的经验法则是,如果它不在循环中并进行计算,则它可能受 IO 限制。任何访问网络资源、文件系统或等待设备响应的东西都可能是 IO

此外,并非程序中的所有内容都会消耗 CPU 时间。当线程试图从磁盘上的文件读取数据或通过网络发送 TCP/IP 数据包时,它所做的唯一一件事就是将实际工作委托给设备、磁盘或网络适配器,并等待结果。

将一个线程的时间花在等待上是非常昂贵的。即使通过线程休眠并且在等待结果时不消耗 CPU 时间,它也不会真正得到回报,因为它是对系统资源的浪费。

你的请求是IO吗? DB 有点模糊,但答案是肯定的。

TPL Dataflow 与否,您只是不想创建线程或使用等待 IO 绑定任务完成的资源

因此 async/await 模式效果很好,或者您也可以使用 TPL 数据流块。前提是您不会创建大量等待的任务。使用 ActionBlock,您可以配置最大任务数量,并将它们重复用于同时位于缓冲区中等待任务的所有项目。

例子

var block = new ActionBlock<MySomething>(
    mySomething => MyMethodAsync(mySomething),
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 50 });

foreach (var something in ListOfSomethings)
{
    block.Post(something );
}

block.Complete();
await block.Completion;