c# async await行为不符合预期
本文关键字:不符合 async await | 更新日期: 2023-09-27 18:07:23
我有一个c#项目,它基本上由以下3个类组成。它应该异步读取本地数据库(sqlite)并继续主进程。虽然它不会抛出任何错误,也不会执行db读取。它只执行包含在主进程while(true) {"Doing Stuff on the Main Thread..."}
中的无限循环。似乎主线程没有等待异步进程。提前感谢。
class DatabaseAccessor
{
static void Main(string[] args)
{
var inq = new InquireDatabaseAsync();
inq.DoWork();
while (true)
{
Console.WriteLine("Doing Stuff on the Main Thread...");
}
}
}
public class InquireDatabaseAsync
{
public async Task DoWork()
{
await Task.Run(() =>
{
LongRunningOperation();
});
}
private static async Task LongRunningOperation()
{
Data_connection2 dbobject = new Data_connection2();
SQLiteConnection m_dbConnection = new SQLiteConnection();
m_dbConnection.ConnectionString = dbobject.datalocation2();
m_dbConnection.Open();
string sql = "SELECT * FROM Commands WHERE Id = (SELECT MAX(Id) FROM Commands)";
SQLiteCommand SQLcommand = new SQLiteCommand(sql, m_dbConnection);
var instruct = await ExecuteLoopTaskAsync(SQLcommand);
}
public async static Task<string> ExecuteLoopTaskAsync(SQLiteCommand sqlCommand)
{
while (true)
{
System.Threading.Thread.Sleep(1000);
var reader = sqlCommand.ExecuteReader();
while (reader.Read())
Console.WriteLine("Id: " + reader["Id"] + "'tInstruction: " + reader["Instruction"] + "'tCellular: " + reader["Cellular"] + "'tTimestamp: " + reader["Timestamp"]);
}
return "Finished...";
}
}
class Data_connection2
{
public string datalocation2()
{
String dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
return "Data Source=" + dir + "''database9.sqlite";
}
}
这一行返回一个Task
:
inq.DoWork();
但是没有对Task
对象做过任何事情。因此,它异步启动任务,并且消费代码不会阻塞它。如果您确实想阻塞它(在这种情况下您可能会这样做),您可以等待任务:
inq.DoWork().Wait();
虽然内部工作可能比我解释的(或者我现在完全掌握的)更复杂,但这个有效的应该具有与使用
相同的观察行为:await inq.DoWork();
但是由于封闭方法不是async
,那么您不能使用该语法。
基本上考虑的范式,事情应该是"异步所有的方式"。这意味着在任何给定的异步调用堆栈的顶层应该有一些东西来管理Task
。对于WinForms、WPF、ASP等技术。. NET等,有内置的机制来做到这一点。对于一款主机应用,你的设计基本上要简单得多。main()
方法是最顶层的方法,需要在堆栈上管理它下面的Tasks
方法。
你可能想做的是,
static void Main(string[] args)
{
var enquiry = new InquireDatabaseAsync().DoWork();
while (!enquiry.IsCompleted)
{
Console.WriteLine("Doing Stuff on the Main Thread...");
}
// In case there were any exceptions.
enquiry.Wait();
}
这段代码有几个问题。考虑使用如下内容:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication6
{
class DatabaseAccessor
{
static async void Main(string[] args)
{
await Task.Run(() =>
{
InquireDatabaseAsync.LongRunningOperation();
});
}
}
public static class InquireDatabaseAsync
{
public static void LongRunningOperation()
{
Data_connection2 dbobject = new Data_connection2();
SQLiteConnection m_dbConnection = new SQLiteConnection();
m_dbConnection.ConnectionString = dbobject.datalocation2();
m_dbConnection.Open();
string sql = "SELECT * FROM Commands WHERE Id = (SELECT MAX(Id) FROM Commands)";
SQLiteCommand SQLcommand = new SQLiteCommand(sql, m_dbConnection);
while (true)
{
System.Threading.Thread.Sleep(1000);
var reader = sqlCommand.ExecuteReader();
while (reader.Read())
Console.WriteLine("Id: " + reader["Id"] + "'tInstruction: " + reader["Instruction"] + "'tCellular: " + reader["Cellular"] + "'tTimestamp: " + reader["Timestamp"]);
break;
}
Console.WriteLine("Finished.");
}
}
class Data_connection2
{
public string datalocation2()
{
String dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
return "Data Source=" + dir + "''database9.sqlite";
}
}
}
虽然DoWork
在内部等待任务,但它立即返回给调用者!因此,如果调用者想要在继续之前等待任务终止,则必须再次等待。
inq.DoWork().Wait();