0

我建立了一个基本的WCF控制台服务器应用程序。我的目标是以并行方式处理对它的多个调用,但当前版本按顺序处理它们。拨打异步WCF服务的顺序执行

请多多包涵,因为有代码遵循一堵墙,但它是非常基本的东西。我很难孤立,因为它是一个相当大的VS解决方案的一部分。

我已经走了下来TPL和异步的路/等待关键字,我基本上了解和喜欢。

服务接口:

<ServiceContract()> 
Public Interface IGetBackendData 

    <OperationContract> 
    Function SendRequest(request As Request) As Task(Of RequestResponse) 

    <OperationContract> 
    Function GetNextPackage(serverJobID As Guid) As Task(Of PackageBase) 

End Interface 

代理:

Public Class imBackendServerProxy 
    Inherits ClientBase(Of IGetBackendData) 
    Implements IGetBackendData 

    Public Function SendRequest(request As Request) As Task(Of RequestResponse) Implements IGetBackendData.SendRequest 
     Return Channel.SendRequest(request) 
    End Function 

    Public Function GetNextPackage(serverJobID As Guid) As Task(Of PackageBase) Implements IGetBackendData.GetNextPackage 
     Return Channel.GetNextPackage(serverJobID) 
    End Function 
End Class 

和实现:

Public Class GetDataService 
    Implements IGetBackendData 

    Private ActiveJobs As New Dictionary(Of Guid, ServiceJobBase) 

    Private Function ProcessRequest(request As Request) As RequestResponse 
     Dim newJob As ServiceJobBase 

     Select Case request.Command.CommandType 
      Case ImagiroQueryLanguage.CommandTypes.CommandHello 
       newJob = New HelloJob 
      Case Else 
       Throw New ArgumentException("Do not know how to process request") 
     End Select 

     If newJob IsNot Nothing Then 
      newJob.AssignedRequest = request 
      ActiveJobs.Add(newJob.ID, newJob) 
      Return newJob.GetResponse() 
     End If 

     Throw New ArgumentException("job could not be started") 
    End Function 

    Public Async Function SendRequest(request As Request) As Task(Of RequestResponse) Implements IGetBackendData.SendRequest 
     Console.WriteLine("Request recieved") 
     Dim mytask As Task(Of RequestResponse) = Task.Factory.StartNew(Function() ProcessRequest(request)) 
     Await Task.Delay(1500) 
     Return Await mytask.ConfigureAwait(True) 

    End Function 


    Private Function GenerateNextPackage(jobid As Guid) As PackageBase 
     If Not ActiveJobs.ContainsKey(jobid) Then 
      Throw New ArgumentException("job could Not be found") 
     End If 

     Dim nextPackage As PackageBase = ActiveJobs(jobid).GetNextPackage() 
     If TypeOf (nextPackage) Is PackageEnd Then 
      ActiveJobs.Remove(jobid) 
     End If 
     Return nextPackage 
    End Function 

    Public Async Function GetNextPackage(serverTaskID As Guid) As Task(Of PackageBase) Implements IGetBackendData.GetNextPackage 
     Dim mytask As Task(Of PackageBase) = Task.Factory.StartNew(Of PackageBase)(Function() GenerateNextPackage(serverTaskID)) 
     Await Task.Delay(1500) 
     Return Await mytask.ConfigureAwait(True) 
    End Function 
End Class 

“请求” 对象包含一个 “命令” 对象(源自CommandBase)以及其他信息。 “Package”对象(源自PackageBase)包含要从服务器传输到客户端的数据。

的通信是如何工作的基本思路是这样的:

1. "Request" phase 
Client --Request--> Server 
Client <--GUID A -- Server 

2. "Data" phase 
Client -- GUID A --> Server 
Client <--DataOrStop-- Server 

3. Repeat step 2. until Server says stop. 

要消耗数据和请求响应,我有以下类:

Public Class DataReceiver 
    Public Event DataPackageRecieved(sender As Object, arg As DataPackageReceivedEventArgs) 
    Public Event EndOfTransmission(sender As Object, arg As EventArgs) 

    Public Sub New(response As RequestResponse, proxy As imBackendServerProxy, dataRecieved As DataPackageRecievedEventHandler, endOfTransmission As EndOfTransmissionEventHandler) 
     ID = response.JobID 
     p = proxy 

     AddHandler Me.DataPackageRecieved, dataRecieved 
     AddHandler Me.EndOfTransmission, endOfTransmission 

     FetchData() 
    End Sub 

    Public Property ID As Guid 
    Private p As imBackendServerProxy 

    Private Sub FetchData() 
     Dim t As Task(Of PackageBase) = Task.Factory.StartNew(Of PackageBase)(Function() p.GetNextPackage(ID).Result) 
     Debug.Print("Waiting for Result FetchData") 
     t.ContinueWith(AddressOf DoneFetching) 
    End Sub 

    Public Delegate Sub ProcessDataPackageDelegate(recievedDataPackage As PackageBase) 

    Public Property ProcessDataPackage As ProcessDataPackageDelegate 

    Private Sub DoneFetching(arg As Task(Of PackageBase)) 
     If arg.IsCompleted Then 
      If TypeOf (arg.Result) Is PackageEnd Then 
       RaiseEvent EndOfTransmission(Me, Nothing) 
      Else 
       RaiseEvent DataPackageRecieved(Me, New DataPackageReceivedEventArgs With {.DataPackage = arg.Result}) 
       FetchData() 
      End If 
     End If 
    End Sub 

End Class 

在我的WPF测试客户端应用程序我有一个按钮,我可以发送请求到服务器。 HelloCommand(源自CommandBase)类用于将整数“n”传输到服务器。然后,服务器响应于每个n后面GetNextPackageHelloPackage(来自PackageBase衍生)调用的最后用EndPackage(来自PackageBase导出)。

在ServiceJob对象中处理此逻辑(从ServiceJobBase派生) - 基本上每个“Command”对象都有一个对应的“ServiceJob”对象,该对象又将相应的“Package”对象发送到顺序客户端请求。

作为客户端处理“数据请求”的需要“的顺序性”,即所述GetNextPackage功能顺序呼叫,这些呼叫将永远不会重叠。但是我非常喜欢两个或多个分别调用GetNextPackage的调用序列和它们各自的“ServiceJobs” - 在服务器上并行执行。这并没有发生。

HelloServiceJob类添加一个简单的计数器以轻松识别每个请求,按一下WPF客户端上的按钮,在服务器上产生以下输出,而UI保持响应。

Request recieved (0) 
Sending HelloPackage - 6 remaining (0) 
Sending HelloPackage - 5 remaining (0) 
Sending HelloPackage - 4 remaining (0) 
Sending HelloPackage - 3 remaining (0) 
Sending HelloPackage - 2 remaining (0) 
Sending HelloPackage - 1 remaining (0) 
Sending HelloPackage - 0 remaining (0) 
Sending no more HelloPackages 

如预期的那样每行之间有1.5秒。

三个快速连续压机产生了服务器上的以下输出,而UI响应停留。

Request recieved (1) 
Request recieved (2) 
Request recieved (3) 
Sending HelloPackage - 6 remaining (1) 
Sending HelloPackage - 6 remaining (2) 
Sending HelloPackage - 6 remaining (3) 
Sending HelloPackage - 5 remaining (1) 
Sending HelloPackage - 5 remaining (2) 
Sending HelloPackage - 5 remaining (3) 
Sending HelloPackage - 4 remaining (1) 
Sending HelloPackage - 4 remaining (2) 
Sending HelloPackage - 4 remaining (3) 
Sending HelloPackage - 3 remaining (1) 
Sending HelloPackage - 3 remaining (2) 
Sending HelloPackage - 3 remaining (3) 
Sending HelloPackage - 2 remaining (1) 
Sending HelloPackage - 2 remaining (2) 
Sending HelloPackage - 2 remaining (3) 
Sending HelloPackage - 1 remaining (1) 
Sending HelloPackage - 1 remaining (2) 
Sending HelloPackage - 1 remaining (3) 
Sending HelloPackage - 0 remaining (1) 
Sending HelloPackage - 0 remaining (2) 
Sending HelloPackage - 0 remaining 
Sending no more HelloPackages (1) 
Sending no more HelloPackages (2) 
Sending no more HelloPackages (3) 

虽然顺序预计,每行花费1.5秒执行,客户机和服务器永远只在一个时间上交换消息。

阅读了很多文章后,我比任何东西都更加困惑。我无法确定我需要做什么才能使三个“作业”并行执行,即使这是完全错误的方法,或者这是一个简单的配置错误。

我在同一台机器上运行服务器和客户机,使用netTcpBinding,如果我正确理解它是必需的,并且适用于客户机和服务器之间的多个并行请求。

我已阅读并(希望)了解下面的文章,但我看不出这相当于我的情况:tasks are still not threads and async is not parallel

我怎样才能让那些接听电话的不同线程运行的作业然后?我完全知道Return Await声明只是等待执行完成,但这不是问题。我想要的是其中三条语句等待并行完成,但服务器和客户端之间的管道似乎只能一次保存一条消息?

谢谢大家的时间和意见,我真的很感激。

回答