私は基本的なWCFコンソールサーバーアプリケーションを構築しました。私の目標は、複数の呼び出しを並行して処理することですが、現在のバージョンではそれらを順次処理します。async WCFへの呼び出しは順番に実行されます
次のコードの壁があるので、私に同行してください。しかし、かなり基本的なものです。非常に大きなVSソリューションの一部であるため、私が分離するのは難しいです。
私は基本的に理解して好きなTPLとasync/awaitキーワードの道を辿りました。
サービス・インターフェース:
<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
A "要求" オブジェクトが由来 "コマンド" オブジェクトを(含まれていますCommandBase
)と追加情報 "Package"オブジェクト(PackageBase
から派生)には、サーバーからクライアントに送信されるデータが含まれています。
通信が動作するようになっているかの基本的な考え方は、このようなものです:私のWPFで
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
:データと要求応答を消費する
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.
、私は以下のクラスを持っていますテストクライアントアプリケーション私は、サーバーにリクエストを送ることができるボタンを持っています。 (CommandBase
から派生した)クラスを使用して、整数 "n"をサーバーに転送します。次に、サーバは、HelloPackage
(PackageBase
から派生)、最後にEndPackage
(PackageBase
から派生したもの)の次のn GetNextPackage
コールのそれぞれに応答します。
ロジックはServiceJobオブジェクト(ServiceJobBase
から派生)で処理されます。基本的にすべての "Command"オブジェクトには対応する "ServiceJob"オブジェクトがあり、対応する "Package"オブジェクトが順次クライアント要求に送信されます。
クライアントが「データ要求」の必要な「連続性」すなわちGetNextPackage
関数への連続呼び出しを処理するので、これらの呼び出しは重複しません。しかし、私は、GetNextPackage
とそれぞれの "ServiceJobs"への2つ以上の別々の呼び出しをサーバ上で並列に実行することを非常に嫌うでしょう。そして、それは起こっていない。
HelloServiceJob
クラスに単純なカウンタを追加すると、各リクエストを簡単に識別できるようになります.WPFクライアントのボタンを1回押すと、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秒があります。
3回連続して押すと、サーバー上で次の出力が生成され、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秒かかりますが、クライアントとサーバーは一度にメッセージを交換するだけです。
多くの記事を読んだ後、私は何よりも混乱しています。 3つの「ジョブ」を並行して実行するために必要なことを特定することはできません。これについては全く間違った方法であるのか、それとも単純な構成エラーであるのかということではありません。
サーバーとクライアントを同じマシン上で実行しています。netTcpBinding
を使用しています。クライアントとサーバー間の複数の並列要求に正しく対応する必要があります。
私が読んで、(うまくいけば)次の記事を理解し、私は、これは私の場合に変換する方法を見ていないしている:tasks are still not threads and async is not parallel
どのように私はコールに応答しているジョブが異なるのスレッド上で実行することができますそれで?私は、Return Await
ステートメントが実行が完了するのをただ待つことを完全に承知していますが、これは問題ではありません。私が望むのは、これらのステートメントのうちの3つです並行して完了するのを待っていますしかし、サーバーとクライアントの間のパイプラインは一度に1つのメッセージを保持するようです?
ありがとう、私はあなたに時間と入力をいただき、本当にありがとうございます。