2017-10-13 5 views
0

私はC#のスレッド世界に慣れていません。私は連続したようにスレッドを行うさまざまな方法があることを読んでいます。コールコール中にC#でスレッディングする

私のシナリオは以下の通りです。どちらがより適していますか?

私は複雑なオブジェクトのリストを持っています。私は各オブジェクト[put of body]のPUTエンドポイントへの呼び出しを別々に行います。リストには10​​00個以上のオブジェクトがあります。そして、私はすべてのオブジェクトを1つに渡すことができないので、putエンドポイントへのすべての呼び出しで各オブジェクトを渡す必要があります。このようにして、1000個のオブジェクトがある場合は、個別に1000個の呼び出しを行う必要があります。

各put呼び出しは互いに独立していますが、各呼び出しから応答のプロパティを戻す必要があります。

私は上記のスレッドの概念を適用することを考えていましたが、どのスレッドをどのように実行するのかはわかりませんでした。

ご意見をいただければ幸いです。

ありがとうございます。

以下のコメントに従って、 メソッドシグネチャをここに置き、詳細を追加します。

私はIEnumerable<CamelList>です。各ラクダについて、私はプットリクエストコールを行い、各コールの応答からテーブルを更新する必要があります。私はこのリストを受け入れる新しいメソッドを記述し、以下の2つのメソッドを使用して呼び出しと更新テーブルを作成します。私は確実に、私は同時に100以上の呼び出しをしていないし、呼び出しているAPIは同じユーザーが毎分100回呼び出すことができます。

は、我々はHTTP呼び出しは通常、そのHTTPメソッドすでに非同期であるHttpClient classを、使用して作られています

+0

最初にサポートされている最も古いバージョンの.NETは4.5.2で、HTTPコールは 'HttpClient'で行われます。次に、HttpClientのメソッドはすべて*非同期です。たとえば、 'HttpClient.PutAsync()'がバックグラウンドで実行されます。スレッドをバックグラウンドで実行するためにスレッドを使用する必要はありません。あなたは 'myUrlObjectPairss.Select(data => client.PutAsync(data.url、data.Content))。ToArray()'と書いて、すべての呼び出しを並行して開始することもできます。 –

+0

悪いです。私たちはC#6を使用しています。私は誤って他のC#4を追加しました。 – Vicky

+0

@Vicky - あなたが追加した署名のタイプが一貫していません。これがあなたの本当のコードであるという方法はありません。助けが必要な場合は、可能な限り簡単に回答できるように努力してください。私たちには[mcve]が必要です。 – Enigmativity

答えて

1

public void updateInTable(Entity Camel); //updates the table.として私たちは、メソッドを持っている public Camel SendRequest(handler, uri, route, Camel); //basically takes all the parameters and provide you the Camel.

ような方法があります。独自のスレッドやタスクを作成する必要はありません。

すべての非同期メソッドは、TaskまたはTask<T> value. You need to use theを返します。keyword to await for the operation to complete asynchronously - that means the thread is released until the operation completes. When that happens, execution resumes after the await`を返します。

PUTリクエストの書き込み方法は、hereです。例では、例えば、文字列にProductクラスをシリアル化し、正しいコンテンツタイプにStringContentクラスを作成するために必要な定型コードを減らすためにPutAsJsonAsyncメソッドを使用しています。

var response = await client.PutAsJsonAsync($"api/products/{product.Id}", product); 
response.EnsureSuccessStatusCode(); 

あなたは1000個の製品を入れたい場合は、すべてのあなた製品の配列やリストが必要です。あなたは、複数の呼び出しを行うためにLINQを使用して、彼らは最後に返す作業を待つことができます。

var callTasks = myProducts.Select(product=>client.PutAsJsonAsync($"api/products/{product.Id}", product); 
var responses = await Task.WhenAll(callTasks); 

これはあなたがいずれかが成功したかどうかをチェックすることができます前に終了するすべての要求を待つ必要があることを意味します。あなたは、応答自体を待つSelectの体を変更することができます。

var callTasks = myProducts.Select(async product=>{ 
     var response=await client.PutAsJsonAsync($"api/products/{product.Id}", product); 
     if (!response.IsSuccessStatusCode) 
     { 
      //Log the error     
     } 
     return response.StatusCode; 
}); 
var responses=await Task.WhenAll(callTasks); 

それは、しかし別の方法にラムダをCONVERするなどPutProductAsync良いでしょう:

async Task<HttpStatusCode> PutProduct(Product product,HttpClient client) 
{ 
      var response=await client.PutAsJsonAsync($"api/products/{product.Id}", product); 
      if (!response.IsSuccessStatusCode) 
      { 
       //Log the error     
      } 
      return response.StatusCode; 
}; 

var callTasks = myProducts.Select(product=>PutProductAsync(product)); 
var responses=await Task.WhenAll(callTasks); 
+0

ありがとう@Panagiotis Kanavos。私が呼び出したり消費したりする予定のAPIだけが、特定のIDから100分程度の呼び出しを1分程度しか許さないということだけです。その場合、例えばwaitやthread.sleepを2倍の時間入れておくとよいでしょう。次の100回のコールを行う前に2分。バッファ時間を考慮してダブルと言った。あるいはこれを行うための他の良い方法がありますか? – Vicky

0

私はMicrosoftのを使用することをお勧めするつもりですこのための反応的な枠組み。ビットを取得するには、 "System.Reactive"をNuGetする必要があります。

その後、あなたはこれを行うことができます。

var urls = new string[1000]; //somehow populated; 

Func<string, HttpContent, IObservable<string>> putCall = (u, c) => 
    Observable 
     .Using(
      () => new HttpClient(), 
      hc => 
       from resp in Observable.FromAsync(() => hc.PutAsync(u, c)) 
       from body in Observable.FromAsync(() => resp.Content.ReadAsStringAsync()) 
       select body); 

var callsPerTimeSpanAllowed = 100; 
var timeSpanAllowed = TimeSpan.FromMinutes(1.0); 

IObservable<IList<string>> bufferedIntervaledUrls = 
    Observable.Zip(
     Observable.Interval(timeSpanAllowed), 
     urls.ToObservable().Buffer(callsPerTimeSpanAllowed), 
     (_, buffered_urls) => buffered_urls); 

var query = 
    from bufferedUrls in bufferedIntervaledUrls 
    from url in bufferedUrls 
    from result in putCall(url, new StringContent("YOURCONTENTHERE")) 
    select new { url, result }; 

IDisposable subscription = 
    query 
     .Subscribe(
      x => { /* do something with each `x.url` & `x.result` */ }, 
      () => { /* do something when it is all finished */ }); 

をこのコードは、ブロック(またはバッファ)100のにURLを破壊し、離れて1分間のタイムライン(または間隔)にそれらを入れています。次に、URLごとにputCallを呼び出し、結果を返します。

これはおそらくあなたのために少し進歩しましたが、私はこの答えが、これがいかにクリーンであるかを見るために役立つかもしれないと考えました。

+0

ありがとう@Enigmativity。私はsystem.reactive拡張に精通していないので、私はそれについて読んでいました。良いアプローチのようだ。しかし、私のチームは、私に再び新しいスレッドであるParallel.Foreachを使用することを提案しています。私はそれを実装することができ、それが良いアプローチでない場合には、その理由を思い付くための長所と短所を見出そうとしています。それ以前に両者を適用したことはありません。あなたがparallel.foreach wayを使ってそれを実装する方法を知っているかどうか教えてください。 401、403、またはいくつかの本物のステータスコードを除いて、応答に問題がある場合は、再試行機能を追加する必要があります。 – Vicky

+0

@Vicky - 'Parallel.For'で時間をバッファリングすることはできません。元の 'urls'のリストを100ブロックに分割し、それらの周りにタイマーを置く必要があります。そして' Parallel.For'を使うことができます。タイマーとグループ化を管理する必要があります。これは自分のコードで簡単に行えます。 – Enigmativity

+0

大丈夫です。理にかなっている。私たちはすでに投稿のためのメソッドを持っています。私はレスポンスで期待しているオブジェクトの型について渡す必要があります。url、逆シリアル化されたオブジェクトを返すhttpClientHandlerです。また、応答が受信されると、私は紺碧のテーブルストレージにいくつかのプロパティを格納する必要があります。上記のコードを更新するにはどうすればよいですか?なぜなら、私はToObservableで見るからです。(......); IObservableインターフェイスのいくつかの組み込みメソッドとして。 – Vicky

関連する問題