0

I made a Python script that simulates a dice and then calculates the relative frequency.

I thought, why not making it multithreaded? Now I'm stuck with the variables. If I run this, it's like the last thread overrides all other results, so it will run multithreaded but only the result of the last thread's taken. Modify the variable tries to your needs, it's set to 8 so you see that there were only 2 random numbers taken and calculated to percent at the end. Don't modify NrThreads, because it always starts 4.

import threading
import random


### CONFIGURE
tries=8
NrThreads=4
triesThread=round(round(tries)/4)
###\CONFIGURE

def ThreadCode():
    global one
    global two
    global three
    global four
    global five
    global six
    one=0
    two=0
    three=0
    four=0
    five=0
    six=0
    for i in range(0, triesThread):
        number=random.randint(1,6)
        if (number == 1):
            one=one+1
        if (number == 2):
            two=two+1
        if (number == 3):
            three=three+1
        if (number == 4):
            four=four+1
        if (number == 5):
            five=five+1
        if (number == 6):
            six=six+1

thread1 = threading.Thread(target=ThreadCode)
thread1.start()
print("Started thread")
thread2 = threading.Thread(target=ThreadCode)
thread2.start()
print("Started thread")
thread3 = threading.Thread(target=ThreadCode)
thread3.start()
print("Started thread")
thread4 = threading.Thread(target=ThreadCode)
thread4.start()
print("Started thread")
thread1.join()
thread2.join()
thread3.join()
thread4.join()

print("Number 1: ", one)
print("Number 2: ", two)
print("Number 3: ", three)
print("Number 4: ", four)
print("Number 5: ", five)
print("Number 6: ", six)

p1=one/tries
print("Probability for number 1: ", p1)

for i in ([one, two, three, four, five, six]):
    print(i/tries,"  ", i/tries*100,"%")
france1
  • 141
  • 2
  • 12
  • If you're doing this to learn about parallelism in python, the @bharel's answer is good, if you want to learn about stats/randomness then I'd suggest looking into the [Multinomial distribution (e.g. in numpy)](https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.multinomial.html) which would do this much more efficiently and with less code – Sam Mason Jan 17 '22 at 21:08

1 Answers1

0

You code has a few issues:

  1. You reset the numbers to 0 in every thread. Every time the function enters they go back to 0.
  2. Your code isn't thread safe. You can't use += from multiple threads on the same number, otherwise it'll overwrite eachother.

Keep in mind this code won't actually be faster because Python has a Global Interpreter Lock (GIL) and you need a lock on all of the additions anyway.

Here's the fixed code:

import threading
import random


### CONFIGURE
tries=8
NrThreads=4
triesThread=round(tries/4)
###\CONFIGURE

lock = threading.Lock()
one=0
two=0
three=0
four=0
five=0
six=0

def ThreadCode():
    global one
    global two
    global three
    global four
    global five
    global six
    for i in range(0, triesThread):
        number=random.randint(1,6)
        with lock:
            match number:
                case 1:
                    one += 1
                case 2:
                    two += 1
                case 3:
                    three += 1
                case 4:
                    four += 1
                case 5:
                    five += 1
                case 6:
                    six += 1

thread1 = threading.Thread(target=ThreadCode)
thread1.start()
print("Started thread")
thread2 = threading.Thread(target=ThreadCode)
thread2.start()
print("Started thread")
thread3 = threading.Thread(target=ThreadCode)
thread3.start()
print("Started thread")
thread4 = threading.Thread(target=ThreadCode)
thread4.start()
print("Started thread")
thread1.join()
thread2.join()
thread3.join()
thread4.join()

print("Number 1: ", one)
print("Number 2: ", two)
print("Number 3: ", three)
print("Number 4: ", four)
print("Number 5: ", five)
print("Number 6: ", six)

p1=one/tries
print("Probability for number 1: ", p1)

for i in ([one, two, three, four, five, six]):
    print(i/tries,"  ", i/tries*100,"%")
Bharel
  • 23,672
  • 5
  • 40
  • 80
  • `Keep in mind this code won't actually be faster because ...`. Can I fix this? – france1 Jan 18 '22 at 21:11
  • `Number 1: 0 Number 2: 2 Number 3: 2 Number 4: 3 Number 5: 4 Number 6: 1 ` Still doesn't seem to be fixed. It is now doing too much. Tries is 8, the result higher than 8: 4 more than 8. With 10 it's only 2 more. Why is this? Because of the rounding in TriesThread? But 8/4 shouldn't need rounding. – france1 Jan 18 '22 at 21:17
  • @france1 unfortunately you can't make it faster. Adding variables requires having a lock. Fixed the count. – Bharel Jan 18 '22 at 21:44
  • It's a bit faster maybe, now needs 120-150% of one cpu core – france1 Jan 19 '22 at 11:26
  • If you wish to make it faster, you can spawn different processes. The overhead for this operation is very high, and will not actually be faster in any less than a few million numbers, but then it'll spread the operations across all cores. – Bharel Jan 19 '22 at 11:35
  • https://stackoverflow.com/questions/46755640/spawning-multiple-processes-with-python Is this what you meant? – france1 Feb 01 '22 at 13:51