在 内Run
,我正在尝试将 10,000 个任务排队。(这只是一个实验,所以我可以更好地理解async await
。)但是第一个循环需要三秒钟才能完成。我希望这会更快,因为我只是想在await
几行之后将任务和它们排队。仍然在Run
,alreadyCompleted
中是正确的,因为任务似乎已经同步运行。最后,仍然在 内Run
,第二个循环需要 1 毫秒才能完成,再次显示任务已经运行。
如何将任务排队运行,同时仍然允许执行通过该Run
方法进行,直到我使用await
?如果我的一些任务在被检查时已经完成,我会理解alreadyCompleted
,但所有任务都完成了似乎很奇怪。此行为在 ASP.NET Core 3、.NET Core 3 控制台和 .NET Framework 控制台之间是一致的。谢谢你。
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
public static class SqlUtility
{
public static async Task Run()
{
const int max = 10000;
Stopwatch sw1 = Stopwatch.StartNew();
Task<int>[] tasks = new Task<int>[max];
for(int i=0;i<max;i++)
{
tasks[i] = GetVideoID();
}
sw1.Stop();//ElapsedMilliseconds: 3169
bool alreadyCompleted = tasks.All(t => t.IsCompletedSuccessfully);//true
Stopwatch sw2 = Stopwatch.StartNew();
for (int i = 0; i < max; i++)
{
await tasks[i].ConfigureAwait(false);
}
sw2.Stop();//ElapsedMilliseconds: 1
}
public static async Task<int> GetVideoID()
{
const string connectionString =
"Server=localhost;Database=[Redacted];Integrated Security=true";
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("VideoID", SqlDbType.Int) { Value = 1000 }
};
const string commandText = "select * from Video where VideoID=@VideoID";
IAsyncEnumerable<object> values = GetValuesAsync(connectionString, parameters, commandText,
CancellationToken.None);
object videoID = await values.FirstAsync().ConfigureAwait(false);//1000
return (int)videoID;
}
public static async IAsyncEnumerable<object> GetValuesAsync(
string connectionString, SqlParameter[] parameters, string commandText,
[EnumeratorCancellation]CancellationToken cancellationToken)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
using (SqlCommand command = new SqlCommand(commandText, connection))
{
command.Parameters.AddRange(parameters);
using (var reader = await command.ExecuteReaderAsync()
.ConfigureAwait(false))
{
while (await reader.ReadAsync().ConfigureAwait(false))
{
yield return reader[0];
}
}
}
}
}
}
更新
在运行 .NET Core 应用程序并使用max
1,000 时,alreadyCompleted
是错误的。实际上,查看IsCompleted
每个任务,alreadyCompleted
当前没有完成的任务。这是我在原始场景中所期望的。
但如果max
设置为 10,000(如其最初的那样),alreadyCompleted
则为假,如上所示。有趣的是,检查tasks[max - 1].IsCompleted
结果false
(首先检查最后一个任务)。 tasks.All(t => t.IsCompletedSuccessfully)
最后检查最后一个结果,此时IsCompleted
是true
.