0

I found a code online and I want to look at it but apparently, multiprocessing doesnt work for Jupyter Notebook. I took the code from this video: https://www.youtube.com/watch?v=IPMcV_IXtX4&t=3s

I tried to put the whole simulate function in another py file and put a if __name__ == '__main__': at the top of the Notebook file for everything after the #simulate comment.

import random
import multiprocessing
import math
import time

        # configuration options
simulations = 6000000
num_decks = 4
shuffle_perc = 75

def simulate(queue, batch_size):
    deck = []

    def new_deck():
        std_deck = [
          # 2  3  4  5  6  7  8  9  10  J   Q   K   A
            2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11,
            2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11,
            2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11,
            2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11,
        ]

        # add more decks
        std_deck = std_deck * num_decks

        random.shuffle(std_deck)

        return std_deck[:]

    def play_hand():
        dealer_cards = []
        player_cards = []

        # deal initial cards
        player_cards.append(deck.pop(0))
        dealer_cards.append(deck.pop(0))
        player_cards.append(deck.pop(0))
        dealer_cards.append(deck.pop(0))

        # deal player to 12 or higher
        while sum(player_cards) < 12:
            player_cards.append(deck.pop(0))

        # deal dealer on soft 17
        while sum(dealer_cards) < 18:
            exit = False
            # check for soft 17
            if sum(dealer_cards) == 17:
                exit = True
                # check for an ace and convert to 1 if found
                for i, card in enumerate(dealer_cards):
                    if card == 11:
                        exit = False
                        dealer_cards[i] = 1

            if exit:
                break

            dealer_cards.append(deck.pop(0))

        p_sum = sum(player_cards)
        d_sum = sum(dealer_cards)

        # dealer bust
        if d_sum > 21:
            return 1;
        # dealer tie
        if d_sum == p_sum:
            return 0;
        # dealer win
        if d_sum > p_sum:
            return -1;
        # dealer lose
        if d_sum < p_sum:
            return 1

    # starting deck
    deck = new_deck()

    # play hands
    win = 0
    draw = 0
    lose = 0
    for i in range(0, batch_size):
        # reshuffle cards at shuffle_perc percentage
        if (float(len(deck)) / (52 * num_decks)) * 100 < shuffle_perc:
            deck = new_deck()

        # play hand
        result = play_hand()

        # tally results
        if result == 1:
            win += 1
        if result == 0:
            draw += 1
        if result == -1:
            lose += 1

    # add everything to the final results
    queue.put([win, draw, lose])


start_time = time.time()

# simulate
cpus = multiprocessing.cpu_count()
batch_size = int(math.ceil(simulations / float(cpus)))

queue = multiprocessing.Queue()

# create n processes
processes = []

for i in range(0, cpus):
    process = multiprocessing.Process(target=simulate, args=(queue, batch_size))
    processes.append(process)
    process.start()

# wait for everything to finish
for proc in processes:
    proc.join()

finish_time = time.time() - start_time

# get totals
win = 0
draw = 0
lose = 0

for i in range(0, cpus):
    results = queue.get()
    win += results[0]
    draw += results[1]
    lose += results[2]

print
print ('  cores used: %d' % cpus)
print ('  total simulations: %d' % simulations)
print ('  simulations/s: %d' % (float(simulations) / finish_time))
print ('  execution time: %.2fs' % finish_time)
print ('  win percentage: %.2f%%'  % ((win / float(simulations)) * 100))
print ('  draw percentage: %.2f%%' % ((draw / float(simulations)) * 100))
print ('  lose percentage: %.2f%%' % ((lose / float(simulations)) * 100))
print
Aaron
  • 10,133
  • 1
  • 24
  • 40
  • Does this answer your question? [Iterating over dictionaries using 'for' loops](https://stackoverflow.com/questions/3294889/iterating-over-dictionaries-using-for-loops) –  Feb 27 '21 at 23:58
  • IPython notebooks are similar to running code in a live interpreter, so the concept of the `__main__` file is a little muddy. It is generally recommended to put all multiprocessing code into a library you then import into IPython. This is less of a problem with linux or MacOS because you can switch to using "fork" as the start method. When you need things to "just work" I always recommend using the actual python interpreter rather than IPython or some other IDE. – Aaron Mar 01 '21 at 00:06
  • [This](https://medium.com/@grvsinghal/speed-up-your-python-code-using-multiprocessing-on-windows-and-jupyter-or-ipython-2714b49d6fac) blog post on medium has some more details, and a few useful links – Aaron Mar 01 '21 at 00:08
  • Have you looked at `ipyparallel`? https://ipyparallel.readthedocs.io/en/latest/ – Mark Moretto Mar 01 '21 at 00:09

0 Answers0