7

ここに私の質問があります。一定数までスレッドを開始したい。100としましょう。これにより、スレッドの開始が開始され、実行中のスレッドの数が継続的にチェックされます。最大数に達すると、新しいスレッドの開始を停止します。ただし、適切なチェック間隔または完了したスレッドを使用すると、シグナルが送信され、新しいスレッドが開始されます。

このようにして、私は常に特定の数のスレッドを実行します。

私はこれをsleepとpermanentwhileを使用して管理しました。だから私は与えられた間隔で実行中のスレッドの総数をチェックし続け、スレッドが完了したら、それを破棄して新しいスレッドを開始します。

しかし、私の解決策は適切な方法として私に来ていません。完了したスレッドがシグナルを送信し、スレッドの最大数のしきい値を下回っている場合は、チェッカーが新しいスレッドを開始する方がよいと思います。

多くのスレッドプールの例を見ましたが、それらのほとんどには、実行中のスレッドの最大数を含むキューに入れられたプールが含まれていません。私が言いたいのは、彼らは完了するまでスレッドを開始し続けるということです。しかし、私が収穫する500kのURLを持っているとしましょう。スレッドプールを使用して、それらすべてをforループで開始することはできません。

プラットフォームはc#4.5WPFアプリケーションです

そして、ここに私の解決策があります。実際、私はもっと良いものを探しています。これを改善していません。

private void Button_Click_4(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        startCrawler();
    });
}

void startCrawler()
{
    int irMaximumThreadcount = 100;
    List<Task> lstStartedThreads = new List<Task>();
    while (true)
    {
        for (int i = 0; i < lstStartedThreads.Count; i++)
        {
            if (lstStartedThreads[i].IsCompleted == true)
            {
                lstStartedThreads[i].Dispose();
                lstStartedThreads.RemoveAt(i);
            }
        }

        if (lstStartedThreads.Count < irMaximumThreadcount)
        {
            var vrTask = Task.Factory.StartNew(() =>
            {
                func_myTask();
            });
            lstStartedThreads.Add(vrTask);
        }

        System.Threading.Thread.Sleep(50);
    }
}

void func_myTask()
{

}
4

5 に答える 5

6

個人的には、これにPLINQを使用します。具体的には、同時実行の数を渡された値に制限するWithDegreeOfParallelismメソッドを使用します。

private IEnumerable<Action> InfiniteFunctions()
{
    while(true)
    {
        yield return func_myTask;
    }
}

private void Button_Click_4(object sender, RoutedEventArgs e)
{
    int irMaximumThreadcount = 100;
    InfiniteFunctions()
        .AsParallel()
        .WithDegreeOfParallelism(irMaximumThreadcount)
        .ForAll(f => f());
}

編集:実際にドキュメントを読むと、irMaximumThreadCountは最大64にしかできないようですので、注意してください。

編集2:わかりました、見栄えが良く、制限されていないプロパティを含むパラメータがParallel.ForEach必要なようです-チェックしてください。したがって、コードは次のようになります。ParallelOptionsMaxDegreeOfParallelism

private void CrawlWebsite(string url)
{
    //Implementation here
}

private void Button_Click_4(object sender, RoutedEventArgs e)
{
    var options = new ParallelOptions() 
    { 
        MaxDegreeOfParallelism = 2000 
    };

    Parallel.ForEach(massiveListOfUrls, options, CrawlWebsite);
}
于 2013-03-03T02:19:57.797 に答える
4

タスクとスレッドを混同しています。タスクはスレッドではありません。各タスクが独自のスレッドを持つという保証はありません

実際、TPL(タスク並列ライブラリ)はある種のキューです。Funcつまり、所有しActionているオブジェクトごとにタスクを作成して開始するだけです。実際に作成されるスレッドの数を制御する簡単な方法はありません。

ただし、TPLがタスクをキューに入れ、さらにロジックを適用してスレッドプールのスレッド間で作業のバランスを取るため、オーバーヘッドをほとんどかけずに多くのタスクを作成できます。

一部のタスクを次々に実行する必要がある場合は、Task.ContinueWithそれらをエンキューするために使用できます。Task.Factory.ContinueWhenAnyまたはで新しいタスクを開始することもできTask.Factory.ContinueWhenAllます。

これは、作成する並列タスクの数を制御する方法の手がかりにもなります。必要な数のタスクを作成し、残りのタスクをでキューに入れるだけですContinueWhenAny。タスクが終了するたびに、次のタスクが開始されます。

繰り返しますが、TPLはスレッドプール内のスレッド間で作業のバランスを取ります。とにかく考慮する必要があるのは、ディスクI/Oやインターネット接続などの他のリソースの使用です。同じリソースを同時に使用しようとするタスクが多数あると、プログラムの速度が大幅に低下する可能性があります。

于 2013-03-03T03:14:51.647 に答える
1

.NET 4.0では、この状況に理想的な同時実行管理が組み込まれたコレクションがいくつか導入されました。ブロッキングコレクションは、whileループでスリープするよりも効率的です。次に、ブロッキングキューから読み取るxスレッドを生成します。

BlockingCollection<string> queue = new BlockingCollection<string>(listOfUrls);

for (int x=0; x < MaxThreads; x++)
{
    Task.Factory.StartNew(() => 
    {
        while (true)
        {
            string url = queue.Take(); // blocks until url is available
            // process url;
        }
    }, TaskCreationOptions.LongRunning);
}

タスクに長時間実行のマークを付けて、スレッドプールを使用する代わりに独自のスレッドを作成するようにします。先入れ先出しが必要な場合はConcurrentQueue<T>、ブロッキングコレクションコンストラクターにを渡すことができます。http://msdn.microsoft.com/en-us/library/dd287085.aspx

于 2013-03-03T03:09:28.097 に答える
0

正確な答えではありませんが、これは正しい方向にあなたを導くかもしれないと思います。

まず、Thread.Joinを見てください。特に、このページの下部にある簡単な例を見てください。このアプローチはThread.Sleep()よりも優れており、目的により適しています。私は、スリープの代わりに「マネージャー」スレッドに参加することを考えています。

目的に合う場合と合わない場合がある2番目のオプションは、新しいTasksライブラリです。最新バージョンのフレームワークを使用しているため、このオプションを使用できますが、タスクライブラリによって作成される実際のスレッド数を制御することはできないと思います。基盤となるスケジューラに基づいて、その値を自動的に選択します。ただし、興味深いと思われるParallelOptions.MaxDegreeOfParallelismという名前のオプションがあります。

于 2013-03-03T02:20:29.823 に答える
0

タスク/スレッドプールを自分で管理し、スレッドが完了するのを待って、すぐに新しいスレッドを開始できます。

MAX_THREAD_ALLOWED = 100;
List<Task> tasks = new List<Task>();
for (int i = 0; i < 1000; i++)
{
    tasks.Add(Task.Run(() => { Foo(i); }));
    if (i == MAX_THREAD_ALLOWED)
    {
        Task.WaitAny(tasks.ToArray());
        MAX_THREAD_ALLOWED++;
    }
}
于 2019-05-15T09:40:04.273 に答える