0

学校では先週マルチスレッドを開始しましたが、すでにマルチプロセッシングを行っていますが、少し迷っているので、問題を説明します。演習では、カジノがゲームに勝つ頻度を知ることができるように、10000ゲームをシミュレートするカジノゲームシミュレーターを作成する必要があります。だから私はシミュレーターをコーディングしました、そして私はゲームを実行するための5つの方法を持っています:

static void game(Croupier croupier)
{
    croupier.createNewCardDeck();
    croupier.shuffleCards();
    croupier.giveCardsToPlayers();
    croupier.countPlayerPoints();
    croupier.displayResults();
}

10000回の反復の古典的なforループでゲームを呼び出すと、正常に実行され、約2秒かかり、銀行は50%の確率で勝ちます。

Parallel.Forを使用すると、複数のプロセスが同じカードパックを同時に編集しようとしているため、shuffleCardsでクラッシュします。

私の最初のアイデアは、シャッフルカードにミューテックスを配置することでしたが、並列プログラミングを使用するポイントが速度を上げることであった場合、シミュレーションが遅くなります。そこで、さまざまなプロセスでデータを分離することを考えました(10000回の反復ではなく、4つのプロセスで2500を実行し、すべてのループに独自のディーラー、プレーヤー、カードなどがあります)。

この問題を解決する最良の方法は何だと思いますか?同じデータを使用する並列作業の処理方法を説明する簡単なチュートリアルはありますか?どのソリューションを選択しますか?ありがとう

編集:ShuffleCardメソッド

        List<Card> randomList = new List<Card>();

        Random r = new Random();
        int randomIndex = 0;

        while (_cards.Count > 0)
        {
            randomIndex = r.Next(0, _cards.Count); //Choose a random object in the list
            randomList.Add(_cards[randomIndex]); //add it to the new, random list
            _cards.RemoveAt(randomIndex); //remove to avoid duplicates
        }
        return randomList;

したがって、はい_cardsはcroupierのプライベートプロパティです(これはthis._cards = shuffleCards()と呼ばれ、すべてのプロセスが同じカードリストを持っています

4

4 に答える 4

6

あなたのアイデアは進むべき道です:各「処理ユニット」(つまり、スレッド、タスク)に独自のゲームテーブル(ディーラー、プレーヤー、カード)を与えます。実際のカジノと同じように、データを共有しないため、互いに独立して、すべてを同時にプレイしながら、必要な数のゲームテーブルを作成できます。ゲームが終了するたびに、結果は銀行に転送されます(そのうちの1つだけがあります)。したがって、(批判的なセクションと)同期する必要があるのは、結果をバンクに集約することだけです。

この例は、並列プログラミングの簡単な例です。現実の世界は、対応するクラスとアルゴリズムにかなり直感的にモデル化できるためです。

于 2012-11-16T09:13:16.173 に答える
0

各スレッドに独自のコレクションのセットを与えるか、独自のスレッドロックを実装する並行コレクションを実装します。

于 2012-11-16T09:22:08.023 に答える
0

そのため、10000回の反復ではなく、4つのプロセスで2500回実行します

タスクとデータの並列処理を一緒に使用できます。たとえば、

        int noOfProcess = 4;
        Task[] t = new Task[noOfProcess];
        for (int i = 0; i < noOfProcess; i++)
        {
           t[i]= Task.Factory.StartNew(() =>
            {
                Parallel.For(0, 2500, (v) => game(..));
            });
        }
        Task.WaitAll(t); //If Synchronous is needed.

共有メモリの場所への書き込みは避けてください。並列プログラミングを使用しているときに、このmsdnでいくつかの落とし穴を確認してください。

于 2012-11-16T12:08:53.277 に答える
0

以前の答えは確かに正しいです。目標は、できるだけ早く実行するために作業を分割することです。つまり、コードを並行して実行できるように、コードを並行して設計します。

各実行では、次のようになります。

  • ディーラー
  • プレイ中のゲーム
  • 一度にCroupierごとに1つのゲームのみ。
  • ゲームの結果

並行性に関する2つの主な決定は、次のとおりです。

  • ゲーム間でCroupiersを共有または配布するにはどうすればよいですか?
  • 結果はどのように共有されますか?

Croupierのさまざまなオプションは次のとおりです。

  • Croupierが1つしかない場合、同時実行性はなくなります。一度にプレイできるゲームは1つだけです。
  • ゲームごとに1つのCroupierを持つことができます。そうすれば、理論的には各ゲームを同時に実行できます。
  • 処理ユニットごとに1つのCroupierを使用できます。これにより、できるだけ多くのゲームを実行できるようになりますが、生の処理以外の要因がある可能性があるため、ゲームごとに1つのCroupierほどバランスが取れない可能性があります。結果の書き込みが長いIO操作であったが、CPUを集中的に使用しなかった場合を想像してみてください。より多くのゲームを実行することもできますが、代わりにCroupierは結果が終了するのを待っています。

結果については、次のことができます。

  • 結果を受け取ったときに、いくつかのストリームに出力します。これがコンソールの場合、出力が文字化けしやすくなります。
  • 結果を順番に処理する一部のコンシューマーに結果を出力します。これは、ゲームに影響を与えることなく結果の状態を返すことができるため、より適切なオプションです。

したがって、全体的な意思決定は常に行われる必要があります。ホスティングシステムが可能な限り最高の状態で実行できるように、コードを可能な限り同時実行しやすいものにするにはどうすればよいですか。

以下の例では、処理ユニットごとにCroupierを選択しました。これは、それが優れているためではなく、他の回答に示されていなかったためです。

これらのアイデアのいくつかを示すサンプルコードを次に示します。

void Main()
{
    const int NUMBER_OF_GAMES = 10000;

    // this is how we have a Croupier per thread.
    var threadLocalCroupier = new ThreadLocal<Croupier>(() => new Croupier());

    var results = from gameNumber in Enumerable.Range(0, NUMBER_OF_GAMES).AsParallel()
                let croupier = threadLocalCroupier.Value
                select game(croupier, gameNumber);

    foreach (var result in results) {
        Console.WriteLine("Game done {0}", result.GameNumber);
        // display or analyse results.
    }
}

static ResultOfGame game(Croupier croupier, int gameNumber)
{
    croupier.createNewCardDeck(gameNumber);
    croupier.shuffleCards();
    croupier.giveCardsToPlayers();
    croupier.countPlayerPoints();
    var results = croupier.getResults();

    return results;
}

class ResultOfGame {

    public int GameNumber { get; private set; }

    public ResultOfGame(int gameNumber) 
    {
        this.GameNumber = gameNumber;
    }

}

// Define other methods and classes here
class Croupier {

private int currentGame;

    public void createNewCardDeck(int gameNumber) {this.currentGame = gameNumber;}
    public void shuffleCards() {}
    public void giveCardsToPlayers() {}
    public void countPlayerPoints() {}
    public ResultOfGame getResults() {
        return new ResultOfGame(this.currentGame);
    }
}
于 2012-11-16T23:28:24.317 に答える