2017-01-31 10 views
-1

私はこれに似たコードを書いています(私はここでstackoverflowに変更したので、おそらくタイプミスがあります)。非同期プロパティのアクセスを待つ

  1. は私がRename()に値を更新する前にGetName()結果を送信し、このリスナーにPacketType.Rename以降PacketType.GetName を送信し、それが終了する可能性があることを知っています。 "注文"を確実にするために、 ロジックの前に両方のメソッドでロックオブジェクトを使用する必要がありますか?私は実行を呼び出し、Rename()が と呼ばれ、コードが NetworkStreamからPacketType.GetNameを取得する前に、したがって、Rename()内の最初の行にロックが常に が呼ばれるべき待つまでBeginReceive()タスク は、次のメッセージを読んで起動しないと仮定することができますし、電話はGetName()を待っていますか?
  2. 同じ
  3. PacketType.Renameが一緒に10回送信、その可能Rename()方法 がで同時に実行されているように、コードのリーチは、Rename()を待っていたら、次のいずれか を取得するためにExecute()とバックを実行し、BeginReceive()上のいずれかによってパケット1 を取得します複数のタスク。 このケースのように値を更新する最新のものはどれですか(すべて の名前が同じです)、または更新された値は の名前のようには関係ありません。
  4. 私の非同期メソッドでサービス/リポジトリパターンを使用して、 データベースに対してCRUDを実行する場合、サービス/リポジトリはローカル変数とメソッドパラメータのみを使用しますが、MockConnectionHandler注射された特性として?各タスクは、これらを独立して、同じサービス/リポジトリを実行する他のタスクから保護する必要がありますか?
  5. 明白なことは何も避けてください。

public class Listener : IListener 
{ 
    public string Name {get;set;} 
    public int Connected {get;set;} 

    ... 
    private async Task Listen() 
    { 
    while (!_Token.IsCancellationRequested) 
    { 
     tcpClient = await _Listener.AcceptTcpClientAsync().ConfigureAwait(false); 

     Connected++; 
     IConnectionHandler connectionHandler = _ClientPool.Receive(); 
     connectionHandler.TcpClient = tcpClient; 
     connectionHandler.Listener = this; // really is done on the Listener init() 
     connectionHandler.Init(); 
    } 
    } 
} 
public class MockConnectionHandler : IConnectionHandler 
{ 
    public string Name {get;set;} 
    public int Messages {get;set;} 
    public IListener Listener {get;set;} 

    public void Init() 
    { 
    BeginReceive(); 
    } 

    private void BeginReceive() 
    { 
    var receive = Task.Run(async() => 
    { 
     while (true) 
     { 
     readedHeader = await _Stream.ReadAsync(dataHead, 0, headerLength, _DisconnectToken); 
     // get body length from header. 
     readedBody = await _Stream.ReadAsync(dataBody, 0, bodyLength, _DisconnectToken); 

     Task run = Task.Run(() => Execute(headType, dataBody)); 
     } 
    }, _DisconnectToken) 
    .ContinueWith(previous => 
    { 
     _EndReceiving = true; 
    }, TaskContinuationOptions.OnlyOnCanceled); 
    } 

    private async Task Execute(PacketType type, byte[] data) 
    { 
    switch(packetType) 
    { 
     case PacketType.Echo: 
     await SendAsync(new Bag(PacketType.Echo)); 
     case PacketType.Rename: 
     await Rename(); 
     case PacketType.GetName: 
     await GetName(); 
    } 
    } 

    private async Task Rename(byte[] data) 
    { 
    Name = Encoding.UTF8.GetString(data); 
    Listener.Name = Encoding.UTF8.GetString(data); 
    } 

    private async Task GetName() 
    { 
    byte[] data = Encoding.UTF8.GetBytes(Name); 
    SendAsync(new Bag(PacketType.Echo, data)); 
    } 
} 

答えて

1

あなたがやっているようにあなたは、すべての非同期関数に待っていた場合、コードは "syncronously" 実行されますが、potentionally減少レイテンシ。あなたが物事を並行して行うことができ、そのようなすべての非同期メソッドを待っているのではなく、むしろタスクハンドルを保存し、それらのすべての結果が必要なときに後で一連のタスクを待つ。

I.e. asyncMeth1()とasyncMeth2()があり、互いに依存せず/並行して実行できる場合は、それぞれ個別に待つべきではありませんが、Taskオブジェクトを保存して、結果が本当に必要なときに待ってください両方の。

+0

私は悪いですが、 'Execute()'コールを待っていないと思っていましたので、コードを更新して以前の質問で今や意味が分かりました。 – Nauzet

0

タスクでawaitを呼び出すと、コードは呼び出し元に戻ります。タスクが完了すると、信号が送信され、コードはその時点に戻ります。

これは、すべてのタスクでawaitを使用しないことを選択した場合にのみ問題になります。待たずにタスクを実行すると、そのタスクは別のスレッドとしてコードと並行して実行されます。そのタスクを待っている場合は、発信者に戻ります。

どのようにでも;私はあなたが頼んでいると答えていると思います。呼び出し元に戻ることは、待っているタスクに戻ることはありません。それはチェーン内で待つ最初の呼び出しに戻ります。たとえば、タスクを待っているメソッドがある場合、そのメソッドの呼び出し元は自由に実行を継続できます。タスクは、awaitを使用するときのようにキューのように連鎖します。

   → caller continues executing 
caller → method → await task1 → await task2 → await task3 
                ↓ 
              task3 complete 
                ↓ 
           cont task2 ← ------- 
            ↓ 
           task2 complete 
            ↓ 
        cont task1 ← ------ 
         ↓ 
       task1 complete 
         ↓ 
     cont method ← ----- 
      ↓ 
    method complete 
      ↓ 
    (nothing to do) 

タスクのawaitキーワードをスキップするとどこでも、チェーンのそのポイントから呼び出し元になります。

+0

私は悪いですが、 'Execute()'コールを待たずにコードを更新しました。私の以前の質問では意味が分かりました。 – Nauzet