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聲明只是等待執行完成,但這不是問題。我想要的是其中三條語句等待並行完成,但服務器和客戶端之間的管道似乎只能一次保存一條消息?

謝謝大家的時間和意見,我真的很感激。

回答