0

私は基本的な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"をサーバーに転送します。次に、サーバは、HelloPackagePackageBaseから派生)、最後にEndPackagePackageBaseから派生したもの)の次の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つのメッセージを保持するようです?

ありがとう、私はあなたに時間と入力をいただき、本当にありがとうございます。

答えて

関連する問題