在哪里停止使用async / await关键字?
我的DB2 / 400有一个简单的心跳方法:
public bool CheckConnection() { try { using (OleDbConnection db = new OleDbConnection( this.conString )) { OleDbCommand cmd = new OleDbCommand(); cmd.CommandText = "select 1 from sysibm.sysdummy1"; cmd.Connection = db; db.Open(); cmd.ExecuteReader(); db.Close(); return true; } } catch (Exception) { return false; } }
我希望在我的应用程序运行时使用它,当然我不想执行表单的其余部分。
我的主要方法是:
public FrmMain() { InitializeComponent(); PrepareFormTexts(); PrepareFormData(); PrepareStateClass(); CheckDbConnection(); //Initialize Data Access for AS400 Dal = JDE8Dal.Instance; Dal.conString = Properties.Settings.Default.conAS400; //Initialize Icons picCon.Image = Properties.Resources.ledGreen; picStatus.Image = Properties.Resources.ledGreen; // Load recording from file if they exist PrepareRecordings(AppState.DataFileName,'|'); }
CheckDbConnection方法:
private async Task CheckDbConnection() { return await Task.Factory .StartNew(() => Dal.CheckConnection()); }
我认为它运行正常,但我收到警告
警告1由于未等待此调用,因此在完成调用之前将继续执行当前方法。 考虑将’await’运算符应用于调用的结果。
我应该忽略它吗? 我应该在主方法中放异步吗?
更新:在下面讨论后我发现,因为我使用.NET 4.0的异步包,我真的不能让我的dal方法无阻塞。 我唯一能做的就是使用async / await + task.factory.startnew,以便在dal在后台运行时保持我的应用程序正常工作。
代码如下:
public FrmMain() { InitializeComponent(); Load += FormLoadInit; } private async void FormLoadInit(object sender, EventArgs e) { PrepareFormTexts(); PrepareFormData(); PrepareStateClass(); txtLot.Select(); //Initialize Data Access for AS400 Dal = JDE8Dal.Instance; Dal.conString = Properties.Settings.Default.conAS400; // Load recording from file if they exist PrepareRecordings(AppState.DataFileName, '|'); bool cn = await Task.Factory.StartNew(() => Dal.CheckConnection()); //Initialize Icons picCon.Image = cn ? Resources.ledGreen : Resources.ledRed; picStatus.Image = Properties.Resources.ledGreen; }
警告告诉你的是你有效地解雇然后忘记了这个异步任务。 您实际上从未使用过操作的结果,甚至也没有存储Task
本身以允许任何将来的代码依赖于它的结果(甚至知道它何时完成)。
这不会破坏任何东西,但它也不是真的有用。 您也可以不调用该方法。 现在,在你的情况下,这只是一个虚拟列表,所以你需要问自己你想要测试什么。 您是否希望在表单上显示一些虚拟值作为概念certificate? 如果是这样,您的代码将需要一些更改才能实现。
要实际使用查询结果,您需要await
它,而不能在构造函数中执行此操作。 您需要将代码移动到Form Load
事件处理程序并将处理程序标记为async
以便您可以在其中await
。
您遇到的另一个问题是,要创建异步方法,您将启动一个新任务,该任务将在线程池中运行,然后让它执行阻塞方法。 使用async / await模型的主要优点是您不需要这样做。 您应该使用数据库查询方法直接为您提供Task
作为其返回值并且不阻止。 然后,您可以await
这些任务(或只是返回它们),以便您的应用程序在您等待时不会阻塞任何线程。
您的CheckConnection
方法应如下所示:
public async Task CheckConnection() { try { using (OleDbConnection db = new OleDbConnection(this.conString)) { OleDbCommand cmd = new OleDbCommand(); cmd.CommandText = "select 1 from sysibm.sysdummy1"; cmd.Connection = db; db.Open(); await cmd.ExecuteReaderAsync(); return true; } } catch (Exception) { return false; } }
CheckDbConnection
则不需要存在。 没有必要在Task
包装CheckConnection
,因为它已经返回任务。
构造函数不能是Async(至少我每次尝试都会遇到编译错误。但是事件处理程序可以。我认为大多数初始化代码都属于Form.Load处理程序。
public FrmMain() { InitializeComponent(); Load+=OnLoaded; } private async void Onloaded(object sender, EventArgs args) { PrepareFormTexts(); PrepareFormData(); PrepareStateClass(); await CheckDbConnection(); //Initialize Data Access for AS400 Dal = JDE8Dal.Instance; Dal.conString = Properties.Settings.Default.conAS400; //Initialize Icons picCon.Image = Properties.Resources.ledGreen; picStatus.Image = Properties.Resources.ledGreen; // Load recording from file if they exist PrepareRecordings(AppState.DataFileName,'|'); }
public FrmMain() { InitializeComponent(); PrepareFormTexts(); PrepareFormData(); PrepareStateClass(); Task delayTask = CheckDbConnection(); //Initialize Data Access for AS400 Dal = JDE8Dal.Instance; Dal.conString = Properties.Settings.Default.conAS400; //Initialize Icons picCon.Image = Properties.Resources.ledGreen; picStatus.Image = Properties.Resources.ledGreen; // Load recording from file if they exist PrepareRecordings(AppState.DataFileName,'|'); }
为了实现您的范围,您可能应该考虑Reactive Extensions Framework 。 以下是基于您的问题示例的示例实现。 您需要向表单添加标签( label1
和label2
)。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; //get Reactive Extensions and reference them in your project. //Reactive Extensions for .NET (Rx .NET) http://msdn.microsoft.com/en-us/data/gg577610 using System.Reactive.Linq; namespace WindowsFormsApplication2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); Load += Form1_Load; } async void Form1_Load(object sender, EventArgs e) { //do independent stuff PrepareSomeStuff(); //notify the DB checking label1.Text = "Checking DB"; //declare an IObservable IObservable startAsync = Observable.Start (() => CheckConnection()).FirstAsync (); //do some other independent stuff PrepareSomeOtherStuff(); //wait for the IObservable to return data bool isDbReady = await startAsync; label1.Text = "Ready"; } private void PrepareSomeOtherStuff() { //do some other stuff label2.Text += "\r\nDo some other stuff"; } private void PrepareSomeStuff() { //do stuff label2.Text = "Do stuff"; } private bool CheckConnection() { //do stufff System.Threading.Thread.Sleep(5000); return true; } } }