异步调用 WCF 服务并在新任务中等待它

Posted

技术标签:

【中文标题】异步调用 WCF 服务并在新任务中等待它【英文标题】:Call a WCF service Asynchronously and Wait for it in a New Task 【发布时间】:2021-06-20 12:34:49 【问题描述】:

我是基于任务的编程的新手。我必须异步调用 WCF 服务并启动一个任务来等待它,因为我不想在相同的方法中等待,所以我编写了类似这样的代码

void MyMainMethod()

   for(int j=0;j<10; j++)
   

      int I = 100;
      Task<response> res =  _client.GetValueAsnc(request);

       //Do some work

       Task.Run(()=> WaitForResponse(res , I));
    


Async Task WaitForResponse(Task<response> res , int I)

   await res;

   if(res.responsecode == "Success")
   
      //udatateDB...
   
 
   else
   
      //update DB with Error Message..
   

这样,如果我在一个循环中调用此服务 10 次,它将启动 10 个任务并给我响应,而不是在 MyMainMethod() 中等待响应,我将为每个请求启动一个单独的任务。

如果这是正确的方法,或者我在这里犯了一些重大错误,并且如果我需要更多细节来解释这个问题,请告诉我。

提前致谢。

【问题讨论】:

Duplex Services 怎么样? 【参考方案1】:

您尝试实现的目标是一件好事。不阻塞某个主线程是个好主意,而且你这样做的方式会奏效。

但是,如果你这样做,你必须手动控制任务的数量。您可能不希望这个数字太高,否则过多的并行性可能会影响性能。

.net 中有一些类可以通过所谓的线程池来帮助管理任务队列。 您使用已知的最大线程数配置线程池,然后将任务排队到池中。线程池类负责清空队列并将任务分配给池中的空闲线程。

您可以了解更多关于线程池的信息here on ms docs

以下示例来自 MS 文档网站。

using System;
using System.Threading;

public class Example 

    public static void Main() 
    
        // Queue the task.
        ThreadPool.QueueUserWorkItem(ThreadProc);
        Console.WriteLine("Main thread does some work, then sleeps.");
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    

    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo) 
    
        // No state object was passed to QueueUserWorkItem, so stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    

// The example displays output like the following:
//       Main thread does some work, then sleeps.
//       Hello from the thread pool.
//       Main thread exits.

【讨论】:

好的,非常感谢......所以当我们说“但是,如果你这样做,你必须手动控制任务的数量。你可能不希望数字太高,否则太多的并行性可能会损害性能”所以我们如何在这种情况下控制任务数量以及当我们说数字太高时..什么数字可能太高..问我对这个基于任务的异步编程一无所知 过高的数字取决于任务的用途、可用的内核数等。例如,如果任务执行阻塞 CPU 密集型工作,则高于内核数(可能如果您有超线程,则为 2 倍)对性能没有帮助。任务数量没有简单的规则,最好在您实施的特定场景中进行一些测量。在某些情况下,如果您有很多任务执行大量异步工作,它们可以重用物理线程。这一切都由线程池管理,相当复杂。 谢谢 Mirronelli,我会试试这个...非常感谢【参考方案2】:

为什么不在线程池上使用任务并行库。

class Client

    internal async Task<string> GetValueAsnc()
    
        Console.WriteLine("GetValueAsync");
        await Task.Delay(TimeSpan.FromSeconds(2));
        return "success";
    

class Program

    private static readonly Client _client = new Client();

    static void Main(string[] args)
    
        var tasks = new List<Task>();
        for (int j = 0; j < 10; j++)
        
            tasks.Add(WaitForResponse());
        

        Task.WhenAll(tasks);
        Console.WriteLine("Tasks finished");
        Console.ReadLine();
    

    static async Task WaitForResponse()
    
        var res = await _client.GetValueAsnc();

        if (res == "Success")
        
            //udatateDB...
        

        else
        
            //update DB with Error Message..
        
    

它有比ThreadPool更好的api,这样不用担心线程饥饿

【讨论】:

谢谢Cavecode,你能解释一下你的建议和我的代码之间的区别吗?这样我才能更理解它....非常感谢 您需要等待对Task.WhenAll的呼叫...或者您需要使用Task.WaitAll @renu 请在此处查看***.com/questions/1774670/c-sharp-threadpool-vs-tasks 任务只是线程池的包装器,对于大多数用例来说它更好,因为您不必担心控制活动线程数等细节 @CaveCoder 你能告诉我我在代码中遵循的方法是什么。是线程池吗……但我使用的任务有点混乱 @renu 在您的代码上您正在使用任务,只是不是在最正确的方式上,其他答案代码是 ThreadPool

以上是关于异步调用 WCF 服务并在新任务中等待它的主要内容,如果未能解决你的问题,请参考以下文章

同时等待多个具有独立延续的 WCF 异步调用

WCF:尽管调用是异步的,但 DNS 查找会冻结 UI

等待多个异步调用完成?

WCF系列教程之客户端异步调用服务

WCF 异步方法调用返回响应对象

在 iOS 中等待多个网络异步调用