Within Run, I'm trying to queue 10,000 tasks.  (This is just an experiment so I can better understand async await.)  But the first loop takes over three seconds to complete.  I would expect this to be faster since I'm just trying to queue the tasks and await them a few lines later.  Still within Run, alreadyCompleted is true because the tasks seem to have run synchronously.  Finally, still within Run, the second loop takes 1 millisecond to complete, again showing the tasks have already run.
How can I queue tasks to run while still allowing execution to progress through the Run method until I use await?  I would understand if some of my tasks had completed by the time alreadyCompleted gets checked, but it seems weird that all of them have completed.  This behavior is consistent between ASP.NET Core 3, .NET Core 3 Console, and .NET Framework Console.  Thank you.
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];
                    }
                }
            }
        }
    }
}
Update
While running a .NET Core application and using a max of 1,000, alreadyCompleted is false.  In fact, looking at IsCompleted of each task, none of the tasks are completed where alreadyCompleted is currently.  This is what I would have expected to happen in my original scenario.
But if max is set to 10,000 (as it was originally), alreadyCompleted is false, just as above.  Interestingly, checking tasks[max - 1].IsCompleted results in false (checking the last task first).  tasks.All(t => t.IsCompletedSuccessfully) checks the last result last, at which point IsCompleted is true.
 
    