C# 如何等待wait/async方法完成
我有以下异步方法:C# 如何等待wait/async方法完成,c#,multithreading,task-parallel-library,async-await,C#,Multithreading,Task Parallel Library,Async Await,我有以下异步方法: private async void ProcessSearch() { // get catalogs on first search if (_invoiceTypes == null && _invoiceAccounts == null) { var confWcf = new Data.ConfigurationWCF(); _invoiceTypes = await confWcf.GetIn
private async void ProcessSearch()
{
// get catalogs on first search
if (_invoiceTypes == null && _invoiceAccounts == null)
{
var confWcf = new Data.ConfigurationWCF();
_invoiceTypes = await confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
_invoiceAccounts = await confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
confWcf.Dispose();
}
var seekWcf = new DataSeekWCF();
_ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
seekWcf.Dispose();
if (_ds != null)
{
SetupInvoiceGrid();
}
}
我不想执行SetupInvoiceGrid,直到\u invoiceTypes、\u invoiceAccounts和\u ds完成
有线索吗?我做得对吗?我应该使用任务而不是等待吗
我已经想出了这个代码,它看起来很有效,对我来说很好,但不知道它是否正确:
private void btnSearch_Click(object sender, EventArgs e)
{
lock (lockObj)
{
if (_isBusy)
return;
else
_isBusy = true;
}
ShowPleaseWait(Translate("Searching data. Please wait..."));
if (_invoiceTypes == null && _invoiceAccounts == null)
{
var t = GetCatalogs();
t.ContinueWith(t2 =>
{
if (t.IsCompleted) ProcessSearch();
});
}
else
{
ProcessSearch();
}
}
private async Task GetCatalogs()
{
// get catalogs on first search
Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF();
var task1 = confWcf.GetInvoiceTypesAsync(1);
var task2 = confWcf.GetInvoiceAccountsAsync(1);
confWcf.Dispose();
await Task.WhenAll(task1, task2);
_invoiceTypes = task1.Result;
_invoiceAccounts = task2.Result;
if (_invoiceTypes != null)
{
cboInvoiceType.DataSource = _invoiceTypes.Tables["invoice_types"];
cboInvoiceType.DisplayMember = "description";
cboInvoiceType.ValueMember = "code";
}
}
private async void ProcessSearch()
{
var seekWcf = new Data.SeekWCF();
_ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
seekWcf.Dispose();
if (_ds != null)
{
SetupInvoiceGrid();
}
HidePleaseWait();
}
我回答了关于如何处理ProcessSearchAsync
本身的完成的原始(?)问题
为了并行运行任务(如注释中所述),这里修改了您的代码,由于invoiceTypes==null
和\u invoiceAccounts==null
检查,它变得有点复杂。请注意,以下检查的实现方式略微改变了逻辑(以前,只有当_invoiceTypes和_invoiceAccounts都为null时,才会执行WCF调用-如果其中只有一个为null怎么办?)
private async Task ProcessSearchAsync()
{
Data.ConfigurationWCF confWcf=新数据.ConfigurationWCF();
任务t1;
任务t2;
如果(_invoiceTypes==null)
t1=confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
其他的
{
var tsc1=新任务完成源();
t1=tsc1.任务;
tsc1.SetResult(_invoiceTypes);
}
如果(_invoiceAccounts==null)
t2=confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
其他的
{
var tsc2=新任务完成源();
t2=tsc2.任务;
tsc2.设置结果(_发票账户);
}
DataSeekWCF seekWcf=新的DataSeekWCF();
任务t3=seekWcf.SearchInvoiceAdminAsync(新Guid(cboEmployer.Value.ToString()),新Guid(cboGroup.Value.ToString()),txtSearchInvoiceNumber.Text,chkSearchLike.Checked,txtSearchFolio.Text,Convert.ToInt32(txtYear.Value));
wait Task.WhenAll(新任务[]{t1,t2,t3});
_invoiceTypes=t1.结果;
_发票账户=t2。结果;
ds=t3.结果;
如果(_ds!=null)
{
SetupInvoiceGrid();
}
confWcf.Dispose();
seekWcf.Dispose();
}
对现有内容的细微更改将满足您的需求。你可以开始新的任务,然后做其他事情,然后在继续之前等待。正如@nosertio所指出的,下面的代码片段还没有准备好生产,因为我没有检查错误条件(比如null
references等等)。关键是,您可以简洁优雅地并行完成这些事情,而不必使用太多的Tasks API。我所做的一个调整值得指出的是,您希望将对Dispose
的调用移动到continuation中(即,在所有wait
s之后)因为如果您在调用*Async方法之后立即尝试Dispose
,您很有可能在得到响应的中途杀死您的WCF客户端,等待
可能会抛出异常(我没有捕捉到)
private async void ProcessSearchAsync()
{
Data.ConfigurationWCF confWcf=新数据.ConfigurationWCF();
任务t1;
任务t2;
//在第一次搜索时获取目录
如果(_invoiceTypes==null&&u invoiceAccounts==null)
{
t1=confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
t2=confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
}
DataSeekWCF seekWcf=新的DataSeekWCF();
任务t3=seekWcf.SearchInvoiceAdminAsync(新Guid(cboEmployer.Value.ToString()),新Guid(cboGroup.Value.ToString()),txtSearchInvoiceNumber.Text,chkSearchLike.Checked,txtSearchFolio.Text,Convert.ToInt32(txtYear.Value));
_发票类型=等待t1;
_发票账户=等待t2;
_ds=等待t3;
如果(_ds!=null)
{
SetupInvoiceGrid();
}
confWcf.Dispose();
seekWcf.Dispose();
}
您是否尝试过运行此程序以查看其是否有效?我觉得很好,这很管用。。但我想用SearchInvoiceAdminAsync并行运行GetInvoiceTypesAsync和GetInvoiceAccountsAsync。因此,这3个方法运行pararell,但我无法执行SetupInvoiceGrid,直到它们全部完成。例如,我希望与SearchInvoiceAdminAsync并行运行GetInvoiceTypesAsync和GetInvoiceAccountsAsync。因此,3个方法运行pararell,但在所有方法完成之前,我无法执行SetupInvoiceGrid。ProcessSearchAsync与我使用的方法相同,只是返回Task而不是void?不,ProcessSearchAsync
只是在声明它时按惯例命名它的方式。我将在答案中展示如何并行运行任务。不,它们不是并行运行的:_invoiceTypes=await t1_发票账户=等待t2_ds=等待t3,而是以串行方式:首先等待t1,然后等待t2,然后等待t3。试试这个:wait Task.WhenAll(新任务[]{t1,t2,t3})_invoiceTypes=t1.结果_发票账户=t2。结果;ds=t3.结果
它甚至比这更复杂,因为像invoiceTypes==null
和\u invoiceAccounts==null
这样的检查是您最初使用的。看新版。你认为我刚才编辑的关于这个问题的更新代码可以吗?谢谢你是的,我觉得你的更新看起来基本上是对的。我认为使用Task.whalll
会使语法比实际需要的更详细,但应该可以。对不起,这是错误的。首先,如果\u invoiceTypes |=null
或\u invoiceAccounts |=null
,它将出现故障,因为t1
和t2
将保持未初始化状态。第二,任务t1、t2、t3不是并行运行的,而是按顺序运行的。第三,如果_invoiceTypes和_invoiceAccounts成员在开始时不为空,那么是否有重用它们的目标?@avo的答案对我来说似乎更正确。@Noseratio是的,你(部分)是对的。我对我的答案编辑了几次,其中一次我的修改中有一两句话说“你想做更多的错误检查”,o
private async Task ProcessSearchAsync()
{
Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF();
Task</*typeof _invoiceTypes*/> t1;
Task</*typeof _invoiceAccounts*/> t2;
if (_invoiceTypes == null)
t1 = confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
else
{
var tsc1 = new TaskCompletionSource</*typeof _invoiceTypes*/>();
t1 = tsc1.Task;
tsc1.SetResult(_invoiceTypes);
}
if ( _invoiceAccounts == null )
t2 = confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
else
{
var tsc2 = new TaskCompletionSource</*typeof _invoiceAccounts*/>();
t2 = tsc2.Task;
tsc2.SetResult(_invoiceAccounts);
}
DataSeekWCF seekWcf = new DataSeekWCF();
Task</*typeof _ds*/> t3 = seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
await Task.WhenAll(new Task[] {t1, t2, t3});
_invoiceTypes = t1.Result;
_invoiceAccounts = t2.Result;
ds = t3.Result;
if (_ds != null)
{
SetupInvoiceGrid();
}
confWcf.Dispose();
seekWcf.Dispose();
}
private async void ProcessSearchAsync()
{
Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF();
Task</*typeof _invoiceTypes*/> t1;
Task</*typeof _invoiceAccounts*/> t2;
// get catalogs on first search
if (_invoiceTypes == null && _invoiceAccounts == null)
{
t1 = confWcf.GetInvoiceTypesAsync(MainForm.State.Entity);
t2 = confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity);
}
DataSeekWCF seekWcf = new DataSeekWCF();
Task</*typeof _ds*/> t3 = seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
_invoiceTypes = await t1;
_invoiceAccounts = await t2;
_ds = await t3;
if (_ds != null)
{
SetupInvoiceGrid();
}
confWcf.Dispose();
seekWcf.Dispose();
}