#c# #winforms
#c# #winforms
Вопрос:
Я исправил это и искал много веб-сайтов, чтобы получить ответ, но не смог. Если вы можете помочь мне исправить это или в чем причина, по которой этот код не будет работать? Я новичок в этом асинхронном процессе. может быть, здесь есть хорошие ребята, которые могут помочь мне или упростить мой код.
Можете ли вы это исправить, он не будет запускаться при поиске. с этим что-то не так.
public async Task SearchRecord()
{
await Task.Run(async () =>
{
try
{
Invoke((MethodInvoker)delegate
{
_route.Enabled = false;
_delete.Enabled = false;
});
conn.Close();
await conn.OpenAsync();
//For load only
Когда я запускаю это на локальном хосте, все работает нормально. но приведенный ниже код не будет работать.
cmd = new MySqlCommand("SELECT record_tbl.ctrl_num as ctrl_num, record_tbl.sender as sender, record_tbl.subject as subject,record_tbl.serial as serial,record_tbl.Doctype as Doctype, record_tbl.dateofletter as dateofletter, record_tbl.dateofentry as dateofentry, status_tbl.status as status from record_tbl, status_tbl where (sender LIKE '%@Search%' or subject LIKE '%@Search%' or serial LIKE '%@Search%' or Doctype LIKE '%@Search%') AND (record_tbl.ctrl_num = status_tbl.ctrl_num AND status_tbl.status = 'DRAFT' and record_tbl.receiver = '" Properties.Settings.Default.Name "')", conn);
cmd.Parameters.AddWithValue("@Search", _search.Text);
readinfo = await cmd.ExecuteReaderAsync();
while (readinfo.Read())
{
if (readinfo.HasRows)
{
Invoke((MethodInvoker)delegate
{
//_edit.Enabled = true;
_route.Enabled = true;
_delete.Enabled = true;
Data.Add(new AccountData()
{
Control = readinfo.GetInt32("ctrl_num"),
Sender = readinfo.GetString("sender"),
Subject = readinfo.GetString("subject"),
Serial = readinfo.GetString("serial"),
Category = readinfo.GetString("doctype"),
Dateofletter = readinfo.GetDateTime("dateofletter").ToString("yyyy/MM/dd", CultureInfo.GetCultureInfo("en-US")),
Dateofentry = readinfo.GetDateTime("dateofentry").ToString("yyyy/MM/dd", CultureInfo.GetCultureInfo("en-US")),
Status = readinfo.GetString("status")
});
});
}
else
{
}
}
conn.Close();
}
catch (Exception s)
{
MessageBox.Show(s.Message);
Invoke((MethodInvoker)delegate
{
Error.Visible = true;
_route.Enabled = false;
_delete.Enabled = false;
});
conn.Close();
}
finally
{
}
}).ConfigureAwait(true);
Комментарии:
1. Обратите внимание, что строка в вашем вопросе начинается с
>
уценки для цитаты (кто-то еще сказал это, это сообщение об ошибке, которое вы получили, это дословная копия из документации и т. Д.). Я удалил их из вашего вопроса, поскольку цитирование себя странно.2. «не будет работать» слишком расплывчато. Вы получаете сообщение об ошибке? Что?
3. я не очень хорошо говорю по-английски. мои извинения. 🙁
4.
When I run this on Localhost it works fine.
это вообще не работает нормально. Вы запускаете задачу только для того, чтобы немедленно вернуться к потоку пользовательскогоInvoke
интерфейса. Даже после этого вы используете эту задачу для ожидания другой задачи. Ни один пример или учебник не настолько сложен, что должно быть признаком того, что что-то не так5.Для начала полностью удалите
Task.Run
.await
продолжение.OpenAsync()` уже ожидает завершения удаленной задачи без блокировки. После удаленияTask.Run
вам больше не нужноInvoke
. Используйтеusing
блок для соединения вместо того, чтобы закрывать его вручную.using
закроет соединение даже в тех случаях, когдаfinally
оно не будет вызвано
Ответ №1:
Правильный способ написания этого кода :
public async Task SearchRecord()
{
_route.Enabled = false;
_delete.Enabled = false;
var sql=@"SELECT record_tbl.ctrl_num as ctrl_num, record_tbl.sender as sender, record_tbl.subject as subject,record_tbl.serial as serial,record_tbl.Doctype as Doctype, record_tbl.dateofletter as dateofletter, record_tbl.dateofentry as dateofentry, status_tbl.status as status
from record_tbl, status_tbl
where (sender LIKE '%@Search%' or subject LIKE '%@Search%' or serial LIKE '%@Search%' or Doctype LIKE '%@Search%')
AND (record_tbl.ctrl_num = status_tbl.ctrl_num
AND status_tbl.status = 'DRAFT'
and record_tbl.receiver = @receiver)";
try
{
using(var conn=new MySqlConnection(...))
using(var cmd=new MySqlCommand(sql,conn);
{
cmd.Parameters.AddWithValue("@Search", _search.Text);
cmd.Parameters.AddWithValue("@receiver", Properties.Settings.Default.Name);
//Open the connection only when needed
await conn.OpenAsync();
using(var readinfo = await cmd.ExecuteReaderAsync())
{
while (readinfo.Read())
{
Data.Add(new AccountData(){...});
}
_route.Enabled = true;
_delete.Enabled = true;
}
}
}
catch(Exception exc)
{
//Log the error before showing it, just in case
LogTheError(exc.ToString());
MessageBox.Show(exc.Message);
Error.Visible = true;
}
}
Используя библиотеку, подобную Dapper, это можно упростить до :
public async Task SearchRecord()
{
_route.Enabled = false;
_delete.Enabled = false;
var sql=@"SELECT ...";
try
{
using(var conn=new MySqlConnection(...))
{
IEnumerable<AccountData> results=await QueryAsync<AccountData>(sql,
_search.Text,
Properties.Settings.Default.Name);
Data.AddRange(results);
_route.Enabled = true;
_delete.Enabled = true;
}
}
catch(Exception exc)
{
//Log the error before showing it, just in case
LogTheError(exc.ToString());
MessageBox.Show(exc.Message);
Error.Visible = true;
}
}
Объяснение
Нет необходимости Task.Run
запускать и ожидать асинхронные операции. Асинхронные операции уже выполняются либо в другом потоке, либо вообще не используют поток. Ввод-вывод в Windows всегда асинхронный и выполняется ОС. Это включает в себя запись на диск или обмен данными с базой данных по сети.
await
не запускает асинхронную операцию, она ожидает уже выполняемой, не блокируя вызывающий поток. После await
завершения выполнение возвращается к исходному потоку. В случае настольных приложений это поток пользовательского интерфейса.
Invoke()
возвращает выполнение в поток пользовательского интерфейса. Однако при использовании это не требуется await
, поскольку выполнение уже вернулось в поток пользовательского интерфейса.
Соединения должны быть недолговечными, потому что открытое соединение накапливает блокировки и занимает ресурсы на стороне сервера. Длительное сохранение соединения открытым заблокирует другие соединения, что приведет к снижению производительности даже с дюжиной одновременных клиентов.
Это может даже привести к взаимоблокировкам, если два клиента в конечном итоге будут ждать, пока другой освободит свои заблокированные строки. Если, например, два приложения прочитают всю таблицу, а затем попытаются выполнить в нее запись, они, вероятно, перейдут в тупик, потому что каждое из них уже заняло общие блокировки для всех строк таблицы.
Нет причин использовать глобальные подключения. ADO.NET использует объединение соединений, чтобы сделать открытие и закрытие соединений как можно более дешевыми. Когда соединение закрывается, оно не удаляется. Вместо этого ADO.NET сбрасывает его и помещает обратно в пул повторно используемых подключений. Таким образом, открытие нового соединения происходит мгновенно.