我正在测试 C# 8 的异步流,并且似乎当我尝试使用旧的 async/await 模式并返回 Task>时,应用程序运行速度更快。(我使用了秒表进行了测量,尝试运行多次,结果是我提到的旧模式似乎比使用 IAsyncEnumerable 更快)。
以下是我编写的简单控制台应用程序代码 (我也在考虑是否以错误方式从数据库加载数据)。
我想知道,IAsyncEnumerable是否不适用于这种情况,或者在使用IAsyncEnumerable查询数据时出了什么问题?我可能错了,但实际上我期望使用IAsyncEnumerable会更快。 (顺便说一句...差异通常在几百毫秒内)
我尝试了10,000行的示例数据。
以下是填充数据的代码,以防万一...
以下是我编写的简单控制台应用程序代码 (我也在考虑是否以错误方式从数据库加载数据)。
class Program
{
static async Task Main(string[] args)
{
// Using the old pattern
//Stopwatch stopwatch = Stopwatch.StartNew();
//foreach (var person in await LoadDataAsync())
//{
// Console.WriteLine($"Id: {person.Id}, Name: {person.Name}");
//}
//stopwatch.Stop();
//Console.WriteLine(stopwatch.ElapsedMilliseconds);
Stopwatch stopwatch = Stopwatch.StartNew();
await foreach (var person in LoadDataAsyncStream())
{
Console.WriteLine($"Id: {person.Id}, Name: {person.Name}");
}
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
Console.ReadKey();
}
static async Task<IEnumerable<Person>> LoadDataAsync()
{
string connectionString = "Server=localhost; Database=AsyncStreams; Trusted_Connection = True;";
var people = new List<Person>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
//SqlDataReader
await connection.OpenAsync();
string sql = "Select * From Person";
SqlCommand command = new SqlCommand(sql, connection);
using (SqlDataReader dataReader = await command.ExecuteReaderAsync())
{
while (await dataReader.ReadAsync())
{
Person person = new Person();
person.Id = Convert.ToInt32(dataReader[nameof(Person.Id)]);
person.Name = Convert.ToString(dataReader[nameof(Person.Name)]);
person.Address = Convert.ToString(dataReader[nameof(Person.Address)]);
person.Occupation = Convert.ToString(dataReader[nameof(Person.Occupation)]);
person.Birthday = Convert.ToDateTime(dataReader[nameof(Person.Birthday)]);
person.FavoriteColor = Convert.ToString(dataReader[nameof(Person.FavoriteColor)]);
person.Quote = Convert.ToString(dataReader[nameof(Person.Quote)]);
person.Message = Convert.ToString(dataReader[nameof(Person.Message)]);
people.Add(person);
}
}
await connection.CloseAsync();
}
return people;
}
static async IAsyncEnumerable<Person> LoadDataAsyncStream()
{
string connectionString = "Server=localhost; Database=AsyncStreams; Trusted_Connection = True;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
//SqlDataReader
await connection.OpenAsync();
string sql = "Select * From Person";
SqlCommand command = new SqlCommand(sql, connection);
using (SqlDataReader dataReader = await command.ExecuteReaderAsync())
{
while (await dataReader.ReadAsync())
{
Person person = new Person();
person.Id = Convert.ToInt32(dataReader[nameof(Person.Id)]);
person.Name = Convert.ToString(dataReader[nameof(Person.Name)]);
person.Address = Convert.ToString(dataReader[nameof(Person.Address)]);
person.Occupation = Convert.ToString(dataReader[nameof(Person.Occupation)]);
person.Birthday = Convert.ToDateTime(dataReader[nameof(Person.Birthday)]);
person.FavoriteColor = Convert.ToString(dataReader[nameof(Person.FavoriteColor)]);
person.Quote = Convert.ToString(dataReader[nameof(Person.Quote)]);
person.Message = Convert.ToString(dataReader[nameof(Person.Message)]);
yield return person;
}
}
await connection.CloseAsync();
}
}
我想知道,IAsyncEnumerable是否不适用于这种情况,或者在使用IAsyncEnumerable查询数据时出了什么问题?我可能错了,但实际上我期望使用IAsyncEnumerable会更快。 (顺便说一句...差异通常在几百毫秒内)
我尝试了10,000行的示例数据。
以下是填充数据的代码,以防万一...
static async Task InsertDataAsync()
{
string connectionString = "Server=localhost; Database=AsyncStreams; Trusted_Connection = True;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
string sql = $"Insert Into Person (Name, Address, Birthday, Occupation, FavoriteColor, Quote, Message) Values";
for (int i = 0; i < 1000; i++)
{
sql += $"('{"Randel Ramirez " + i}', '{"Address " + i}', '{new DateTime(1989, 4, 26)}', '{"Software Engineer " + i}', '{"Red " + i}', '{"Quote " + i}', '{"Message " + i}'),";
}
using (SqlCommand command = new SqlCommand(sql.Remove(sql.Length - 1), connection))
{
command.CommandType = CommandType.Text;
await connection.OpenAsync();
await command.ExecuteNonQueryAsync();
await connection.CloseAsync();
}
}
}
IAsyncEnumerable
时,你等待每个人。使用Task<IEnumerable>
时,只需等待一次。使用IAsyncEnumerable
的优势是你能够在获取到每个人时看到他们的信息:不必等待所有人都被获取完毕。如果你不需要这样的功能,就不要使用IAsyncEnumerable
。 - canton7IAsyncEnumerable
/Task<IEnumerable>
。在这两种情况下,创建它所需的等待次数是相同的。 - canton7IAsyncEnumerable<T>
实现允许“生成”值的批次,使得对于已经分批的值,MoveNextAsync
可以是同步的。 - Paulo Morgado