2
  1. 接続を使用するメソッドがあります(たとえば、ページをダウンロードするメソッド)。
  2. このメソッドを複数回実行する必要があります(たとえば、1000ページをダウンロードします)。
  3. 同期的かつ順次的な方法でそれを行うには長い時間がかかります。
  4. リソースが限られています(最大8スレッドおよび/または最大50の同時接続)
  5. 私はそれを加速するためにすべてのリソースを使用したいと思います。
  6. 並列化(PLINQ、Parallel Extensionsなど)で問題を解決できることは知っていますが、すでに試しましたが、リソースが不足しているため、このアプローチは失敗します。
  7. リソースを管理しながら、この種のタスクを並列化する車輪の再発明はしたくありません。誰かが以前にそれを実行し、このためのライブラリ/チュートリアルを提供した必要があります。

誰か助けてもらえますか?

非同期呼び出しと並列化を組み合わせてパフォーマンスを最大化すると、更新がさらに複雑になります。これは、Firefoxダウンローダーなどの複数のダウンローダーに実装されており、2つのダウンロードを同時に取得し、そのうちの1つが完了すると、次のファイルを取得します。実装は非常に簡単に思えるかもしれませんが、実装したとき、汎用(WebRequestとDbCommandに便利)にしたり、問題(タイムアウトなど)に対処したりするのに問題がありました。

バウンティハンターバウンティは、信頼性が高く無料の($$).NETライブラリをリンクする最初のライブラリに付与されます。このライブラリは、非同期タスクをHttpWebRequests.BegingetResponseおよびSqlCommand.BeginExecuteNonQueryとして並列化する簡単なC#の方法を提供します。並列化は、N個のタスクが完了するのを待ってから、次のN個を開始する必要はありませんが、最初のN個のタスクの1つが終了するとすぐに新しいタスクを開始する必要があります。メソッドは、タイムアウト処理を提供する必要がありました。

4

11 に答える 11

5

接続のカウントセマフォを調べます。 http://en.wikipedia.org/wiki/Semaphore_(programming)

編集:あなたのコメントに答えるために、.NETFrameworkにはすでに1つあります。http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx

于 2009-01-27T18:15:12.733 に答える
5

Parallel Linq が機能しない理由を詳しく教えてください。

私の見解では、あなたの仕事はPLinqに最適です。8 コアのマシンで実行する場合、PLinq は 8 つのタスクに分割し、残りのすべてのタスクをキューに入れます。

ここにドラフトコードがあります、

PagesToDownload.AsParallel().ForAll(DownloadMethodWithLimitConnections);

PLinq がリソースを消費する理由がわかりません。私のテストによると、PLinq のパフォーマンスは ThreadPool を使用するよりも優れています。

于 2009-02-01T14:22:02.290 に答える
4

CCRを参照してください。ライブラリの学習曲線が少し多すぎると感じるかもしれませんが、これは「正しい」方法です...

于 2009-02-01T14:23:18.387 に答える
3

.NETSystem.Threading.ThreadPoolクラスを使用できます。を使用して、一度にアクティブになるスレッドの最大数を設定できますThreadPool.SetMaxThreads()

于 2009-01-27T18:09:24.820 に答える
3

ここに私が得られないものがあります: あなたは最大 50 接続と言っていますが、8 スレッドしかありません。定義による各接続は「占有」/スレッドで実行されます。つまり、CPU の負荷を軽減するために DMA やその他の魔法を使用していないため、各転送には実行コンテキストが必要です。一度に 50 個の非同期リクエストを起動できる場合は、それを実行してください。非同期読み取り関数の呼び出しには基本的に時間がかからないため、同じスレッドからすべてのリクエストを起動できるはずです。たとえば、8 つのコアがあり、コア全体が各転送専用であることを確認したい場合 (それはおそらく愚かですが、それはあなたのコードなので...)、一度に 8 つの転送しか実行できません。

私の提案は、同期ブロック内で 50 個の非同期要求を起動するだけで、いずれかが完了する前にすべての要求が開始されるようにすることです (計算を単純化します)。次に、ジェレミーが提案するようにカウントセマフォを使用するか、mbeckish が提案するように同期されたキューを使用して、残りの作業を追跡します。async-complete コールバックの最後に、次の接続を開始します (適切な場合)。つまり、50 個の接続を開始し、1 つが終了したら、「完了」イベント ハンドラーを使用して次の接続を起動し、すべての作業が完了するまで続けます。これには、追加のライブラリやフレームワークは必要ありません。

于 2009-02-04T16:12:18.587 に答える
2

非常に短いタスクを除いて、スレッドプールから離れることを強くお勧めします。セマフォを使用する場合は、作業項目コードの先頭ではなく、作業項目をキューに入れているコードのみをブロックするようにしてください。そうしないと、(セマフォの最大数* 2)が次の場合にスレッドプールがすぐにデッドロックされます。最大プールスレッドより大きい。

実際には、プールスレッドのロックを安全に取得することはできません。また、ほとんどの非同期API(または、スレッドプールのカバーの下で非同期操作も実行するHttpWebRequest.GetResponseなどの同期API)を安全に呼び出すこともできません。

于 2009-01-27T19:54:59.757 に答える
2

Jeffrey Richter には、役立つかもしれない Power Threading Library があります。サンプルがぎっしり詰まっており、かなり強力です。接続の簡単なサンプルは見つかりませんでしたが、複数の非同期操作の調整に関して役立つ可能性のある例はたくさんあります。

ここからダウンロードでき、いくつかの記事とサンプルがここにあります。また、このリンクには、同時非同期操作について説明している Jeffrey の詳細な記事があります。

于 2009-02-01T14:20:27.490 に答える
2
  1. フェッチされたページと、まだフェッチする必要があるページを追跡するためのデータ構造を作成します。例えばキュー

  2. Producer/Consumer Queue パターンを使用して、8 つのコンシューマー スレッドをディスパッチしてフェッチを行います。そうすれば、8 スレッドの制限を決して超えないことがわかります。

良い例については、こちらを参照してください。

于 2009-01-27T20:12:24.353 に答える
1

これは、.net 3.5 の基本クラス ライブラリで行う方法です。 SetMinThreads の呼び出しはオプションです。

DoSomethingThatsSlow への置換内でタイムアウトを処理する必要があります

public class ThrottledParallelRunnerTest
{
    public static void Main()
    {
        //since the process is just starting up, we need to boost this
        ThreadPool.SetMinThreads(10, 10);

        IEnumerable<string> args = from i in Enumerable.Range(1, 100)
                                   select "task #" + i;
        ThrottledParallelRun(DoSomethingThatsSlow, args, 8);
    }

    public static void DoSomethingThatsSlow(string urlOrWhatever)
    {
        Console.Out.WriteLine("{1}: began {0}", urlOrWhatever, DateTime.Now.Ticks);
        Thread.Sleep(500);
        Console.Out.WriteLine("{1}: ended {0}", urlOrWhatever, DateTime.Now.Ticks);
    }

    private static void ThrottledParallelRun<T>(Action<T> action, IEnumerable<T> args, int maxThreads)
    {
        //this thing looks after the throttling
        Semaphore semaphore = new Semaphore(maxThreads, maxThreads);

        //wrap the action in a try/finally that releases the semaphore
        Action<T> releasingAction = a =>
                                        {
                                            try
                                            {
                                                action(a);
                                            }
                                            finally
                                            {
                                                semaphore.Release();
                                            }
                                        };

        //store all the IAsyncResult - will help prevent method from returning before completion
        List<IAsyncResult> results = new List<IAsyncResult>();
        foreach (T a in args)
        {
            semaphore.WaitOne();
            results.Add(releasingAction.BeginInvoke(a, null, null));
        }

        //now let's make sure everything's returned. Maybe collate exceptions here?
        foreach (IAsyncResult result in results)
        {
            releasingAction.EndInvoke(result);
        }
    }
}
于 2009-02-06T08:03:54.313 に答える
1

F# 非同期ワークフローを確認する必要があります。

コードを並列ではなく非同期にしたい

非同期とは、ネットワークへのアクセス、Web サービスの呼び出し、その他の一般的な I/O 操作の実行など、呼び出し元のスレッドをブロックする必要のない長時間実行される操作を実行するプログラムを指します。

これは、 C# イテレーターを使用して説明されたこの概念に関する非常に興味深い記事です。

これは、F# と非同期プログラミングに関する優れた本です。

学習曲線は非常に悪いですが (F# 構文、Async<'a> 型、モナドなど、奇妙なものがたくさんあります)、非常に強力なアプローチであり、優れた C# 相互運用性を備えた実生活で使用できます。

ここでの主なアイデアは継続です: いくつかの I/O 操作を待っている間、スレッドに別のことをさせましょう!

于 2009-02-07T03:22:08.310 に答える