我看过一些关于async
和await
的帖子以及这些帖子究竟是如何运作的,但我仍然有点困惑。假设我有两个async
方法,我想确保第二个方法在第一个方法完成后开始。例如,考虑这样的事情:
public async Task MyMethod(Item x)
{
await AddRequest(x); // 1. Add an item asynchronously
// make sure 2 starts after 1 completes
await GetAllRequest(); // 2. get all items asynchronously
}
然后,确定这种情况的正确方法是什么?
更新
为了尝试提供最小,完整和可验证的示例:
我在WCF
应用程序中有2 WPF
个服务与Oracle WebCenter Content
(UCM
)进行通信。这是我的代码的最小版本:
用于添加新客户的UCM服务:
public static async Task<ServiceResult> CheckInCustomer(Customer c)
{
CheckInSoapClient client = new CheckInSoapClient();
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
// an async method in Oracle WebContent services to insert new content
result = await client.CheckInUniversalAsync(c);
}
return new ServiceResult();
}
获取所有客户的UCM服务:
public static async Task<Tuple<ServiceResult, QuickSearchResponse>> GetAllCustomers()
{
ServiceResult error;
var result = new QuickSearchResponse();
SearchSoapClient client = new SearchSoapClient();
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
// an async method in Oracle WebContent services to search for contents
result = await client.QuickSearchAsync(queryString);
}
return new Tuple<ServiceResult, QuickSearchResponse>(error, result);
}
在UI中添加绑定到Button命令的客户异步方法:
private async Task AddCustomer()
{
var result = await CheckInCustomer(NewCustomer);
if (!result.HasError)
await GetAllCustomers();
}
public ICommand AddCustomerCommand
{
get
{
_addCustomerCommand = new RelayCommand(async param => await AddCustomer(), null);
}
}
获取所有客户异步方法(Items
绑定到用户界面中的DataGrid
):
private async Task GetAllCustomers()
{
Items.Clear();
var searchResult = await GetCustomersInfoAsync();
if (!searchResult.HasError)
{
foreach (var item in searchResult)
Items.Add(new CustomerVm(item));
}
}
现在,当我添加新的Customer
时,我希望在DataGrid
中看到新创建的项目,因为我首先插入客户,然后获得所有客户。但是这段代码的行为是随机的,这意味着有时列表会在插入后的几秒钟内显示新创建的客户,有时则不会。
答案 0 :(得分:2)
您提供的代码实际上可以满足您的需求。
public async Task MyMethod(Item x)
{
await AddRequestAsync(x);
await GetAllRequestAsync();
}
但是,如果你在谈论不可预测的非常短暂的&#34;他们之间的延迟,你想确保没有延迟,这是不可能的。
答案 1 :(得分:1)
等待 - (优先,必须在ContinueWith上使用)(TY到@Taffer和@Michael评论) 等待新创建的任务完成,并确保等待任务的执行完成后继续。
您的第一个func AddRequest将在转移到GetAllRequest之前提供结果。
public async Task MyMethod(Item x)
{
await AddRequest(x);
await GetAllRequest();
}
我不明白的是,异步意味着第一个 方法可以保留未完成并执行主任务 继续。因此,第二种方法的某些部分可能会运行 在第一种方法完成之前。
它被称为异步编程,因为当遇到await关键字(类似于迭代器中的yield)时,程序的运行时捕获状态会在等待任务完成后恢复状态,所以继续在正确的上下文中运行。
但是如果你想在第一个任务之后运行它,那么你可以这样做。
使用ContinueWith - 该任务可用的方法允许在任务完成执行后执行代码。简单来说,它允许继续。
public async Task MyMethod(Item x)
{
var req = AddRequest(x).ContinueWith(async (t1) =>
{
await GetAllRequest();
});
}