1

このプログラムは、サイトに行を投稿するメッセージ ポスター アプリケーションです。高速である必要があるため、マルチスレッドを使用する必要がありました。同じ行を取る 2 つのスレッドの確率が可能になります。どうすれば回避できますか? 上記で想定していること以外は、同じIDで投稿された最大11行を見て、これは不可能です...

私が行を取っている方法は次のとおりです:

1- データベースからデータセットを作成....

2-カウンターを作成します、rowCounter = 0

   while (rowCounter < allPostingRows.Tables[0].Rows.Count)
            {

           //  Take rows, and increment rowcounter++
           //  Takes row according to row counter....
          //   get the value from the fields in dataset and run the function:
               postFunction(userName, pass, postUrl, rowCounter, worker, postTitle, postText, postTxtSnippet, groupID, dbID, postON, groupName, groupUrl);
             }

したがって、開始時にこれを実行するために 100 個のスレッドがあると言うと、100 個のスレッドがこのコードに入り、それぞれ行を取り、投稿し、スレッドが投稿して空いているときに をチェックしrowcounter、別の行を取ります。

だから私は上記のロジックを使用して、スレッドに異なる行を与えています.他の方法を考えられなかったので、このアプローチは悪いですか! また、複数のスレッドが同じ行を取ると仮定すると、どうすれば修正できますか?

アップデート

私が考えることができる1つの解決策は、すべての作業が完了した後にランダムな遅延を置くことであり、スレッドは新しい行を取得するのに役立ちますか?

以下のユーザーからの回答後に更新:

したがって、私のコードは次のようになります。

private Object thisLock = new Object();

   lock (thisLock)
            {
    while (rowCounter < allPostingRows.Tables[0].Rows.Count)
            {

           //  Take rows, and increment rowcounter++
           //  Takes row according to row counter....
          //   get the value from the fields in dataset and run the function:
               postFunction(userName, pass, postUrl, rowCounter, worker, postTitle, postText, postTxtSnippet, groupID, dbID, postON, groupName, groupUrl);
             }
          }
4

4 に答える 4

0

はい、このアプローチは「悪い」ものであり、説明した問題のあるスレッドの状況が発生します。実際、カウンターをインクリメントする前に、100 個のスレッドすべてに同じ行を取得させることができます。

私が考えることができる1つの解決策は、すべての作業が完了した後にランダムな遅延を置くことであり、スレッドは新しい行を取得するのに役立ちますか?

批判的ではありませんが、これはどのように解決策だと思いますか? C# のドキュメントでスレッドと同期について読んで、このトピックに精通する ことをお勧めします。

ここにいくつかの提案があります。

1) ワークフローを逆にします。最初にスレッドを作成してデータをフェッチする代わりに、スレッドが作成されたときにメイン プロセスが作業をスレッドに分割します。そうすれば、共有リソースにアクセスしようとしてスレッドが競合することはなく、終了時にスレッドが終了する可能性があり、その時点で新しいスレッドを作成できます。

2) #1 がうまくいかない場合は、上記のコードの while ループを「クリティカル セクション」と見なし、ロック ブロック内に配置する必要があります。 これにより、特定の時間に 1 つのスレッドのみが行をフェッチし、カウンターをインクリメントすることが保証されます。ただし、スレッドの処理速度によっては、プロセスの効率が大幅に低下する可能性があります。

于 2012-08-11T06:40:07.933 に答える
0

2 つ以上のスレッドが同じ行を読み取る可能性があることは明らかです。ただし、クリティカル セクションを保護するためにロック メカニズムを使用できると確信しています。さらに、ADO.NET は非同期タスクをサポートしてパフォーマンスを向上させます。

于 2012-08-11T06:42:03.590 に答える
0

Agree with other commenters about using more intelligent partitioning such as the one provided by Parallel.ForEachr. However, if you still want to use your code, consider putting the counter increment inside a critical region, or use CAS increment. Do it INSIDE the while loop, and not outside. For example:

while (rowCounter < allPostingRows.Tables[0].Rows.Count)
                {
                    Interlocked.Increment(ref rowCounter);
                    //  Take rows, and increment rowcounter++            
                    //  Takes row according to row counter....           
                    //   get the value from the fields in dataset and run the function:                
                    postFunction(userName, pass, postUrl, rowCounter, worker, postTitle, postText, postTxtSnippet, groupID, dbID, postON, groupName, groupUrl);              
                }
于 2012-08-11T16:07:15.130 に答える
0

LBが指摘するように、私Parallel.ForEachはあなたの最善の策だと思います.

ForEach を乱用しないようにするための理由と方法について説明します

実行中のスレッドは、特定の CPU またはコアを使用します。Windows は、任意の数の実行スレッドをサポートしています。スレッドの数は、コアの数をはるかに超える場合があります。各スレッドが CPU バウンドでない場合、これは通常問題にはなりません。これは、通常、多くの処理能力が必要になるためです。CPU バウンド スレッドは、基本的に実行中のコアを 100% 使用しているスレッドです。Windows が 1 つのスレッドからコアを奪って別のスレッドを実行できるようにするたびに、コンテキスト スイッチと呼ばれます。Context Switch は非常に時間がかかります。スレッドを停止し、現在のスレッドのすべてのレジスタとその他の状態情報を保存し、別のスレッドの保存されたレジスタと状態情報をロードしてから、別のスレッドを起動する必要があります。それ自体で1000サイクルもかかると言われています。スレッドが CPU バウンドでない場合、コンテキスト切り替えの可能性は低くなります。ただし、それが発生した場合でも、通常はそれを処理するために多くの CPU サイクルが必要です。複数の CPU バウンド スレッドがある場合、それらは手に入れることができるすべてのサイクルを使用しています。スレッド間を切り替えるためだけにサイクルを取り始めると、実際には時間がかかっていることに気づき始めます。コアより多くの CPU バウンド スレッドがある場合 (つまり、一度に "100" スレッドを実行したい場合)、実際にはすべての作業を並列ではなく順次実行した場合は、同じ量の作業を実行する時間が長くなります。

Parallel.ForEachこれを自動的に行います。コアよりも多くの CPU バウンド スレッドを持つことが悪いことであることを認識しており、適切と思われる数よりも多くのスレッドのみをスピンアップして並列作業を実行します。(通常はコアの数に基づいていますが、TPL で他に何が起こっているかをよりよく把握しているため、使用に関する他の基準がある場合があります)。特定の数のスレッドを使用するように ForEach を強制することはできますが、並列処理の目的が無効になり、パフォーマンスが低下します。

4 つのコア (または 8 つのコア) があり、100 個の CPU バウンド スレッドを実行する場合、コンテキストの切り替えに費やされる CPU 時間は膨大になり、システムがほとんど使用できない状態になる可能性があります。

于 2012-08-11T15:21:52.843 に答える