My experience of solving algorithmic problem of Fizz Buzz Multithreaded.

A photo of Betizazu Alemu looking professional.
Betizazu Alemu
  • 2 min read

Today’s challenge was about multithreading. To be honest, I have no idea how multithreading works in Python, so I struggled to understand the question not only about finding the solution.

The title of the problem was Fizz Buzz Multithreaded.

Problem description

You are given an instance of the class FizzBuzz that has four functions: fizz, buzz, fizzbuzz and number. The same instance of FizzBuzz will be passed to four different threads:

  • Thread A: calls fizz() that should output the word “fizz”.
  • Thread B: calls buzz() that should output the word “buzz”.
  • Thread C: calls fizzbuzz() that should output the word “fizzbuzz”.
  • Thread D: calls number() that should only output the integers.

Modify the given class to output the series [1, 2, "fizz", 4, "buzz", ...] where the ith token (1-indexed) of the series is:

  • “fizzbuzz” if i is divisible by 3 and 5,
  • “fizz” if i is divisible by 3 and not 5,
  • “buzz” if i is divisible by 5 and not 3, or
  • i if i is not divisible by 3 or 5.

Examples

Input: n = 15

Output: [1, 2, "fizz", 4,"buzz", "fizz", 7, 8, "fizz", "buzz", 11, "fizz", 13, 14, "fizzbuzz"]

Input: n = 5

Output: [1, 2, "fizz", 4, "buzz"]

You can find a brief description about the problem here.

Experience

Before writing any code, I googled how multithreading works. After I understood how it works, I tried to fool the system by storing the instance of the functions (i.e., fizz, buzz, fizzbuzz, number) on an instance variable called functions to call them later. Here is the code snippet to clarify what I mean:

python
def number(self, printNumber: 'Callable[[int], None]') -> None:
   for number in range(1, self.n + 1):
       if number % 3 != 0 and number % 5 != 0:
           self.callResults[number] = printNumber
           
   time.sleep(0.1)
   self.checkAndFinish()
   
def checkAndFinish(self):
   if len(self.callResults) == self.n:
       for number, function in self.callResults.items():
           if number % 3 != 0 and number % 5 != 0:
               function(number)
           else:
               function()

All the codes are similar for the functions, the only difference is the condition. After every function is executed it will sleep for 0.1 second and call checkAndFinish function. The problem with this approach is, I can’t call the function while being inside another thread.

I spent almost 2 and a half hours and was about to give up, but in my final trial, I found some code snippets that led me to the solution.

The results

  • Runtime: 40 ms, faster than 91.57% of Python3 online submissions.
  • Memory Usage: 14.6 MB, less than 55.56% of Python3 online submissions.

The code

python
class FizzBuzz:
    def __init__(self, n: int):
        self.n = n
        self.counter = 1
		
    # printFizz() outputs "fizz"
    def fizz(self, printFizz: 'Callable[[], None]') -> None:
        i = self.counter
        while i <= self.n:
            if i % 3 == 0 and i % 5 != 0:
                printFizz()
                self.counter += 1
                
            time.sleep(0.000001)
            i = self.counter
			
    # printBuzz() outputs "buzz"
    def buzz(self, printBuzz: 'Callable[[], None]') -> None:
        i = self.counter
        while i <= self.n:
            if i % 5 == 0 and i % 3 != 0:
                printBuzz()
                self.counter += 1
                
            time.sleep(0.000001)
            i = self.counter
    	
    # printFizzBuzz() outputs "fizzbuzz"
    def fizzbuzz(self, printFizzBuzz: 'Callable[[], None]') -> None:
        i = self.counter
        while i <= self.n:
            if i % 3 == 0 and i % 5 == 0:
                printFizzBuzz()
                self.counter += 1
                
            time.sleep(0.000001)
            i = self.counter
	
    # printNumber(x) outputs "x", where x is an integer.
    def number(self, printNumber: 'Callable[[int], None]') -> None:
        i = self.counter
        while i <= self.n:
            if not (i % 3 == 0 or i % 5 == 0):
                printNumber(i)
                self.counter += 1
                
            time.sleep(0.000001)
            i = self.counter

Discover related blog posts that delve into similar themes, share valuable insights, and offer fresh perspectives.