使用 10 个线程打印升序数字

Print ascending numbers using 10 threads

最近我偶然发现了一个为软件工程师设计的面试问题。问题是:

给定 10 个线程,按顺序打印 1-100,以便线程 1 打印 1、11、21 等 (Python)

无论如何我都不是 Python 方面的专家,但我认为解决方案应该非常简单。然而,我连续 3 个小时都无法解决这个问题,这让我很困惑。到目前为止我想出的代码如下:

import threading, queue

THREADS_NUM = 10
LIMIT = 100

class MyThread(threading.Thread):
    lock = threading.Lock()
    
    def __init__(self, q): 
        threading.Thread.__init__(self) 
        MyThread.lock.acquire() 
        self.id = int(self.name[7:])
        #print("My id is %d" % self.id)
        self.q = q
        MyThread.lock.release()
 
    def run(self):
        MyThread.lock.acquire()
        while True:
            try:
                #print("Right now the queue size is %d" % self.q.qsize())
                current_num = self.q.get()
                if current_num % 10 == self.id:
                    print("%s is now printing %d" % (self.id, current_num)) 
                else:
                    self.q.put(current_num)
            except queue.Empty:
                print("reached the end")
                break
            finally:
                self.q.task_done()
        MyThread.lock.release()

            

#threads = []

q = queue.Queue()
for i in range(1, LIMIT):
    q.put(i)

for i in range(1, THREADS_NUM):
    thread = MyThread(q)
    #threads.append(thread)
    thread.start()

q.join()
 
#for t in threads: 
#    t.join()

经过一番研究后,我发现最简单的选择是使用默认可用的同步 queuethreading 库在 python3 中。这个问题没有说明 library/method 我应该使用什么,所以我愿意接受其他方法。

注意

此代码打印:

1 is now printing 1
1 is now printing 11
1 is now printing 21
1 is now printing 31
1 is now printing 41
1 is now printing 51
1 is now printing 61
1 is now printing 71
1 is now printing 81
1 is now printing 91
...hangs & never exits

好吧,如果我能在我的评论中实现这个想法,我很好奇,它似乎:

#!/usr/bin/env python3.7

import threading


THREADS_NUM = 10
LIMIT = 100


class NumberPrinterThread(threading.Thread):

    def __init__(self, mod_n, initial):
        super().__init__()
        self.mod_n = mod_n
        self.n = initial
        self.e = threading.Event()
        self.next_event = None

    def run(self):
        while True:
            # Wait to be told to print
            self.e.wait()
            # Clear/reset our own event
            self.e.clear()

            print(self.n)

            # Signal the next thread to print
            self.next_event.set()

            # Exit if the next number is too big
            self.n += self.mod_n
            if self.n > LIMIT:
                return


if __name__ == "__main__":
    threads = [NumberPrinterThread(THREADS_NUM, n + 1) for n in range(THREADS_NUM)]
    for i, t in enumerate(threads):
        # Link each thread to the next
        next_thread = threads[(i + 1) % THREADS_NUM]
        t.next_event = next_thread.e

    for t in threads:
        t.start()

    # Signal the first thread
    threads[0].e.set()

    for t in threads:
        t.join()