我建立了一個基本的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後面GetNextPackage
與HelloPackage
(來自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
聲明只是等待執行完成,但這不是問題。我想要的是其中三條語句等待並行完成,但服務器和客戶端之間的管道似乎只能一次保存一條消息?
謝謝大家的時間和意見,我真的很感激。