If I put just only the title of today’s challenge here, you might say, “Nah!! it shouldn’t be considered as a challenge; it’s so easy,” but don’t let the title fool you cause that’s what it does to me.
The title of the problem was “print in order” when I saw it, I was like, “what the hell?!” but when I read the description, I was like, “Ohhh! that shit! 😲😲😲“.
Here is the thing, I got many chances to learn about Event-Driven programming, and every time I didn’t put much of my focus into it cause I thought I don’t need it much. However, if you really think about it, it’s the most crucial skill you need in today’s world because there are so many interactions with calling APIs, accessing data from somewhere, and so forth. Long story short, today’s challenge made me return to my old study materials and notes and do lots of Googling. I am happy that it made me revise my resources.
Problem description
Suppose we have a class:
public class Foo {
public void first() { print("first"); }
public void second() { print("second"); }
public void third() { print("third"); }
}
The same instance of Foo
will be passed to three different threads. Thread A will call first()
, thread B will call second()
, and thread C will call third()
. Design a mechanism and modify the program to ensure that second()
is executed after first()
, and third()
is executed after second()
.
note
We do not know how the threads will be scheduled in the operating system, even though the numbers in the input seem to imply the ordering. The input format you see is mainly to ensure our tests’ comprehensiveness.
Examples
Input: nums = [1, 2, 3]
Output: “firstsecondthird”
Explanation: There are three threads being fired asynchronously. The input
[1, 2, 3]
means thread A callsfirst()
, thread B callssecond()
, and thread C callsthird()
. “firstsecondthird” is the correct output.
Input: nums = [1, 3, 2]
Output: “firstsecondthird”
Explanation: The input
[1, 3, 2]
means thread A callsfirst()
, thread B callsthird()
, and thread C callssecond()
. “firstsecondthird” is the correct output.
You can find a brief description about the problem here.
Experience
At the first trial, I wasn’t thinking about events; what I did was the stupidest solution. I initiated an attribute called state with the value of 1; then I increment it by one at the end of the first and second methods. The reason I did that was, at the first line of each function, I will check if the state is the correct one; then the function will execute; if not, I will return.
The idea is excellent, but I forgot that when I return a function, I am telling the thread that the function is done executing, which means I am not giving him any chance to call it again. I had to think about how to make a function wait; I realized that I could use the sleep function from the time module.
The next problem was finding the right amount of time to make the execution faster. I tried giving a deficient number of seconds like 0.000001, considering it will make the execution faster. The problem with such a number is that since the sleep time is so small, the thread will end up calling the function over and over again within a short period, leading to a massive increase in execution time. After a lot of trials, I found out 0.1 seconds work best.
The results
- Runtime: 80 ms, faster than 68.26% of Python3 online submissions.
- Memory Usage: 14.5 MB, less than 55.81% of Python3 online submissions.
The code
class Foo:
def __init__(self):
self.state = 1
def first(self, printFirst: 'Callable[[], None]') -> None:
while self.state != 1: time.sleep(0.1)
print(self.state)
# printFirst() outputs "first". Do not change or remove this line.
printFirst()
self.state += 1
def second(self, printSecond: 'Callable[[], None]') -> None:
while self.state != 2: time.sleep(0.1)
print(self.state)
# printSecond() outputs "second". Do not change or remove this line.
printSecond()
self.state += 1
def third(self, printThird: 'Callable[[], None]') -> None:
while self.state != 3: time.sleep(0.1)
print(self.state)
# printThird() outputs "third". Do not change or remove this line.
printThird()