Моя проблема основана на реальной проблеме проекта, но я никогда не использовал библиотеку System.Threading.Tasks
или не выполнял никаких серьезных программ, связанных с потоками, поэтому мой вопрос может быть сочетанием недостатка знаний о конкретной библиотеке и более общего непонимания того, что асинхронный действительно означает с точки зрения программирования.
Итак, это мой реальный случай - мне нужно получить данные о пользователе. В моем текущем сценарии это финансовые данные, поэтому позвольте сказать, что мне нужен все Accounts
, all Deposits
и все Consignations
для определенного пользователя. В моем случае это означает запрос миллиона записей для каждого свойства, и каждый запрос относительно медленный сам, однако для извлечения Accounts
в несколько раз медленнее, чем выборка Deposits
. Поэтому я определил три класса для трех банковских продуктов, которые я собираюсь использовать, и когда я хочу получить данные для всех банковских продуктов определенного пользователя, я делаю что-то вроде этого:
List<Account> accounts = GetAccountsForClient(int clientId);
List<Deposit> deposits = GetDepositsForClient(int clientId);
List<Consignation> consignations = GetConsignationsForClient(int clientId);
Итак, проблема начинается здесь. Мне нужно получить все эти три списка одновременно, потому что я собираюсь передать их в представление, где я показываю все данные пользователей. Но поскольку это прямо сейчас, выполнение является синхронным (если я правильно использую этот термин здесь), общее время сбора данных для всех трех продуктов:
Total_Time = Time_To_Get_Accounts + Time_To_Get_Deposits + Time_To_Get_Consignations
Это не хорошо, потому что каждый запрос относительно медленный, поэтому общее время довольно большое, но также, запрос Accounts
занимает гораздо больше времени, чем два других запроса, поэтому идея, которая попала мне в голову сегодня, "Что делать, если я могу выполнять эти запросы одновременно". Может быть, здесь приходит мое самое большое недоразумение в этой теме, но для меня самое близкое к этой идее - сделать их асинхронными, поэтому, возможно, тогда Total_Time
не будет временем самого медленного запроса, но будет намного быстрее, чем сумма всех трех запросы.
Поскольку мой код сложный, я создал простой пример использования, который, как я думаю, отражает то, что я пытаюсь сделать очень хорошо. У меня есть два метода:
public static async Task<int> GetAccounts()
{
int total1 = 0;
using (SqlConnection connection = new SqlConnection(connString))
{
string query1 = "SELECT COUNT(*) FROM [MyDb].[dbo].[Accounts]";
SqlCommand command = new SqlCommand(query1, connection);
connection.Open();
for (int i = 0; i < 19000000; i++)
{
string s = i.ToString();
}
total1 = (int) await command.ExecuteScalarAsync();
Console.WriteLine(total1.ToString());
}
return total1;
}
и второй метод:
public static async Task<int> GetDeposits()
{
int total2 = 0;
using (SqlConnection connection = new SqlConnection(connString))
{
string query2 = "SELECT COUNT(*) FROM [MyDb].[dbo].[Deposits]";
SqlCommand command = new SqlCommand(query2, connection);
connection.Open();
total2 = (int) await command.ExecuteScalarAsync();
Console.WriteLine(total2.ToString());
}
return total2;
}
который я называю следующим образом:
static void Main(string[] args)
{
Console.WriteLine(GetAccounts().Result.ToString());
Console.WriteLine(GetDeposits().Result.ToString());
}
Как вы можете видеть, я сначала вызываю GetAccounts()
, и я замедляю исполнение вниз, поэтому я даю возможность исполнению продолжить следующий метод. Однако я не получаю никакого результата в течение определенного периода времени, а затем я все распечатываю на консоли в то же время.
Итак, проблема - как сделать так, чтобы я не дождался завершения первого метода, чтобы перейти к следующему методу. В общем, структура кода не так важна, и я действительно хочу понять, есть ли способ заставить оба запроса выполнить в одно и то же время. Образец здесь является результатом моих исследований, которые, возможно, могут быть расширены до такой степени, что я получу желаемый результат.
P.S
Я использую ExecuteScalarAsync();
только потому, что начал с метода, который его использовал. На самом деле я буду использовать Scalar
и Reader
.