代码之家  ›  专栏  ›  技术社区  ›  Bahman_Aries

C#如何确保一个异步方法在另一个异步方法之后执行

  •  1
  • Bahman_Aries  · 技术社区  · 7 年前

    我看过一些关于 async await 还有这些是如何工作的,但我还是有点困惑。假设我有两个 异步 方法,我希望确保第二个方法在第一个方法完成后启动。例如,考虑以下情况:

        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 
        }
    

    那么,什么是确保这种情况发生的正确方法?

    更新:

    为了尝试提供一个最小、完整和可验证的示例:

    我有2个 WCF a中的服务 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中按钮命令的客户异步方法:

        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 在UI中):

        private async Task GetAllCustomers()
        {
            Items.Clear();
            var searchResult = await GetCustomersInfoAsync();
            if (!searchResult.HasError)
            {
                foreach (var item in searchResult)
                    Items.Add(new CustomerVm(item));
            }
        }
    

    现在,当我添加新 Customer ,我希望在 数据网格 因为我首先插入客户,然后获取所有客户。但此代码的行为是随机的,这意味着有时列表会在插入几秒钟后显示新创建的客户,有时则不会。

    2 回复  |  直到 7 年前
        1
  •  3
  •   Intellectual Gymnastics Lover    7 年前

    您提供的代码实际上满足了您的需要。

    public async Task MyMethod(Item x)
    {
        await AddRequestAsync(x); 
    
        await GetAllRequestAsync(); 
    }
    

    但是,如果你在谈论他们之间不可预测的“非常非常短”的延迟,并且你想确保没有延迟,那是不可能的。

        2
  •  3
  •   marc_s HarisH Sharma    5 年前

    等候 -(首选,必须在ContinueWith上使用)(TY到@Taffer和@Michael comments)等待新创建的任务完成,并确保在等待任务完成后继续执行。

    您的第一个func AddRequest将在移动到GetAllRequest之前提供结果。

    public async Task MyMethod(Item x)
    {
        await AddRequest(x);
        await GetAllRequest();
    }
    

    我不明白的是,异步意味着 方法可以不完成,也可以不执行主任务 继续。所以第二种方法的某些部分可能会运行 在第一种方法完成之前。

    它之所以称为异步编程,是因为运行时在遇到wait关键字(类似于迭代器中的yield)时捕获程序的状态,并在等待的任务完成后恢复状态,以便继续在正确的上下文上运行。。

    但如果您只想在第一个任务之后运行它,那么您可以这样做。

    使用ContinueWith -它在任务上可用的方法,允许在任务完成执行后执行代码。简单地说,它允许继续。

    public async Task MyMethod(Item x)
    {
        var req = AddRequest(x).ContinueWith(async (t1) =>
                   {
                      await GetAllRequest();
                   }); 
    }