4

誰かが複数のスレッドを作成せずに同時リクエストを行う方法を教えてもらえますか?たとえば、100個のWebリクエストを作成するプログラムが必要であり、いつでも8個を超える同時リクエストは必要ありません。8つの同時リクエストに対して8つのスレッドを作成したくありません。スレッドが非同期リクエストを行うと、同じスレッドを使用して次のリクエストを行うことができます。申し訳ありませんが、これに頭を悩ませることはできません。最善の解決策を見つけたいと思います。はっきりしない場合は、私が話しているリクエストは非同期です。ロックを使用せず、組み込みのクラスを使用して作業を行うソリューションを見たいと思います。

これは私が思いついたコードですが、本来の機能を果たしていません。

Task.Run(async () =>
                        {
                            var outstandingRequests = 0;
                            var requestCount = 0;
                            var tasks = new List<Task>(concurrentRequests);
                            while (requestCount < maxRequests)
                            {
                                if (outstandingRequests < concurrentRequests)
                                {
                                    tasks.Add(svc.GetDataAsync());  // a method that makes an async request
                                    Interlocked.Increment(ref outstandingRequests);
                                }
                                else
                                {
                                    var t = await Task.WhenAny(tasks);                                                                       
                                    Interlocked.Decrement(ref outstandingRequests);
                                    Interlocked.Increment(ref requestCount);
                                }
                            }
                            await Task.WhenAll(tasks);
                        }).Wait();

出力:

[] 1 Sending Request...Received Response 490,835.00 bytes in 15.6 sec
[] 2 Sending Request...
[] 3 Sending Request...
[] 4 Sending Request...
[] 5 Sending Request...
[] 6 Sending Request...
[] 7 Sending Request...
[] 8 Sending Request...
[] 9 Sending Request...

5に設定concurrentRequestsしたので、8つのリクエストを並行して行うため、上記のコードにはいくつかのバグがあります。最初は並行して5つのリクエストしか作成しませんでしたが、1つのリクエストが完了するとすぐに、さらに4つのリクエストが発生しました(あと1つだけ発生するはずでした)。

いくつかのバグを修正する必要がありましたが、すべてうまくいきました。

Task.Run(async () =>
                        {
                            var outstandingRequests = 0;
                            var requestCount = 0;
                            // adding and removing from a List<> at the same time is not thread-safe,
                            // so have to use a SynchronizedCollection<>
                            var tasks = new SynchronizedCollection<Task>();
                            while (requestCount < maxRequests)
                            {
                                if (outstandingRequests < concurrentRequests)
                                {
                                    tasks.Add(svc.GetDataAsync(uri)); // this will be your method that makes async web call and returns a Task to signal completion of async call
                                    Interlocked.Increment(ref outstandingRequests);
                                    Interlocked.Increment(ref requestCount);
                                }
                                else
                                {                                    
                                    **tasks.Remove(await Task.WhenAny(tasks));**
                                    Interlocked.Decrement(ref outstandingRequests);                                    
                                }
                            }
                            await Task.WhenAll(tasks);
                        }).Wait();

それを行うためのより良い方法があれば、私に知らせてください。

4

2 に答える 2

4

Looks like you are trying to reinvent the thread pool. Don't do that - just use existing functionality: http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx
Or you can use async versions of request methods - they are based on the thread pool too.

于 2013-03-17T02:56:42.983 に答える
1

これはどう:

Parallel.Invoke (new ParallelOptions { MaxDegreeOfParallelism = 8 },
    svcs.Select (svc => svc.GetDataAsync ()).ToArray ()) ;

限定同時実行タスク スケジューラの Microsoft 実装のサンプルがここにあります。SO質問を参照してください.

于 2013-03-17T16:08:31.070 に答える