欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于python的多线程的Condition问题,制作了一个实验

程序员文章站 2022-05-02 16:55:51
...


实验代码如下,可以直接运行。实验结论可能跟文档的解释不太一样。

import threading
import time

condi = threading.Condition()
N =1
condi2 = threading.Condition()

def tar01():
    global N
    with condi:
        print('%s is started'%threading.current_thread().name)
        print(N)
        N +=1
        time.sleep(0.1)
        print('in %s,wait01 is triggered'%threading.current_thread().name)
        condi.wait()
        print('in %s,notify 01 is triggered'%threading.current_thread().name)
        condi.notify()
        print('in %s,notify 01 finished'%threading.current_thread().name)


def tar02():
    global N
    with condi:
        print('%s is started'%threading.current_thread().name)
        print(N)
        N +=1
        time.sleep(0.1)
        print('in %s,notify 02 is triggered'%threading.current_thread().name)
        condi.notify()
        print('in %s,wait 02 is triggered'%threading.current_thread().name)
        condi.wait()
        print('in %s,wait 02 finished'%threading.current_thread().name)


def tar03():
    global N
    with condi:
        print('%s is started'%threading.current_thread().name)
        print(N)
        N += 1
        time.sleep(0.1)
        print('in %s,notify 03 is triggered'%threading.current_thread().name)
        condi.notify()
        print('in %s,wait 03 is triggered'%threading.current_thread().name)
        condi.wait()
        print('in %s,wait 03 finished'%threading.current_thread().name)
        # print('in %s,notify 03 is triggered'%threading.current_thread().name)
        # condi.notify()
        # print('in %s,notify 03 finished'%threading.current_thread().name)


def tar04():
    with condi2:
        print('%s is started'%threading.current_thread().name)
        for i in range(1,7,2): #打印1到6之间的基数,因为起始点是1,步长是2
            print(i)
            time.sleep(0.1)
            print('in %s,notify 01 is triggered'%threading.current_thread().name)
            condi2.notify()
            print('in %s,wait 01 is triggered'%threading.current_thread().name)
            condi2.wait()
            print('in %s,wait 01 finished'%threading.current_thread().name)
            # print('in %s,notify 01 is triggered'%threading.current_thread().name)
            # condi2.notify()
            # print('in %s,notify 01 finished'%threading.current_thread().name)


def tar05():
    with condi2:
        print('%s is started'%threading.current_thread().name)
        for i in range(2,7,2): #打印1到6之间的偶数,因为起始点是2,步长是2
            print(i)
            time.sleep(0.1)
            print('in %s,notify 02 is triggered'%threading.current_thread().name)
            condi2.notify()
            print('in %s,wait 02 is triggered'%threading.current_thread().name)
            condi2.wait()
            print('in %s,wait 02 finished'%threading.current_thread().name)

key = input('press Enter to go mod A,else: press other key:  ')

if key == '':
    for i in range(2):
        # 这个for循环的含义就是每轮开启3个线程,由于第1轮循环开启的时候,第1轮循环开启的线程尚未结束,
        # 所以第2轮同时又开启了3个循环。并且,由于第二轮开启的时候,第一轮循环里的第一个受制于condition的函数尚未结束,
        # 并且这6个线程在代码中还受制于同一个condition,所以他们在实际运行中也是受制于同一个condition的
        # 所以,他们必然要依次开启一同结束。受到同一个condition制约的线程是同时结束的
        threading.Thread(target=tar01).start()
        threading.Thread(target=tar02).start()
        threading.Thread(target=tar03).start()
else:
    # t1 = threading.Thread(target= tar01) # 这三次个线程即使没有被使用,也被创建了出来,并占用了头两个线程的编号
    # t2 = threading.Thread(target= tar02)
    # t3 = threading.Thread(target= tar03)

    threading.Thread(target=tar04).start()
    threading.Thread(target=tar05).start()

# print('+++++++++++++++finished+++++++++++++++')

# 运行结果证明:
# 1. 在循环执行两次两个tar01和tar02时,tar02唤醒的原因是tar02.wait(),
# 2. notify()函数是用来告诉Condition,如果再没有新的线程需要等待的,那么本线程可以结束了的,
#    以及如果线程池里只剩下一个处于等待状态的线程时,这个线程也被**并运行这个线程剩余的代码
#下面是不同情况的具体总结:

# +++++++++++++++++++
# 对于顺序执行tar01 tar02 tart03的情况
if 1 == 1:
    pass
    # press Enter to go mod A,else: press other key:
    # Thread-1 is started
    # 1
    # in Thread-1,wait01 is going to work
    # Thread-2 is started
    # 2
    # in Thread-2,notify 02 is going to work
    # in Thread-2,wait 02 is going to  work
    # Thread-3 is started
    # 3
    # in Thread-3,notify 03 is going to work
    # in Thread-3,wait 03 is going to  work
    # Thread-4 is started
    # 4
    # in Thread-4,wait01 is going to work
    # Thread-5 is started
    # 5
    # in Thread-5,notify 02 is going to work
    # in Thread-5,wait 02 is going to  work
    # Thread-6 is started
    # 6
    # in Thread-6,notify 03 is going to work
    # in Thread-6,wait 03 is going to  work
    # in Thread-1,notify 01 is going to  work
    # in Thread-1,notify 01 finished
    # in Thread-5,wait 02 finished
    # in Thread-2,wait 02 finished
    # in Thread-3,wait 03 finished
    # in Thread-4,notify 01 is going to  work
    # in Thread-4,notify 01 finished
    # in Thread-6,wait 03 finished
    #
    # Process finished with exit code 0
# +++++++++++++++++++++++++++++++++++++++++
#对于tar04和tar05的情况:假如每个函数循环的总次数是偶数,
if 1 == 1:
    pass
    # 比如:
    # tar04执行for循环的次数为3次,for i range(1,7,2) 循环打印的是1,3,5
    # tar05执行for循环的次数为3次,for i range(2,7,2) 循环打印的是2,4,6
    # 那么tar04写成先wait再notify,tar05写成先notify再wait的话,这样的两个线程是可以都结束的。
    # 程序运行结果如下:
    # press Enter to go mod A,else: press other key:  p
    # Thread-1 is started
    # 1
    # in Thread-1,wait 01 is triggered #这两部清晰的证明wait会导致下一个Condition函数被release
    # Thread-2 is started
    # 2
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is triggered
    # in Thread-1,wait 01 finished
    # in Thread-1,notify 01 is triggered
    # in Thread-1,notify 01 finished
    # 3
    # in Thread-1,wait 01 is triggered
    # in Thread-2,wait 02 finished
    # 4
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is triggered
    # in Thread-1,wait 01 finished
    # in Thread-1,notify 01 is triggered
    # in Thread-1,notify 01 finished
    # 5
    # in Thread-1,wait 01 is triggered
    # in Thread-2,wait 02 finished
    # 6
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is triggered
    # in Thread-1,wait 01 finished
    # in Thread-1,notify 01 is triggered
    # in Thread-1,notify 01 finished
    # in Thread-2,wait 02 finished

    # Process finished with exit code 0
# +++++++++++++++++++++++++++++++++++++++++
#如果把tar04和tar05都写成先nofity再wait的形式;
if 1 == 1:
    pass
    # 就会导致在执行最后一步循环时,tar04结束之后没有运行notify函数通知处于等待状态的tar05被唤醒,
    # 从而一直hang在那里,运行结果如下:
    # press Enter to go mod A,else: press other key:  p
    # Thread-1 is started
    # 1
    # in Thread-1,notify 01 is triggered
    # in Thread-1,wait 01 is triggered
    # Thread-2 is started
    # 2
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is triggered
    # in Thread-1,wait 01 finished
    # 3
    # in Thread-1,notify 01 is triggered
    # in Thread-1,wait 01 is triggered
    # in Thread-2,wait 02 finished
    # 4
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is triggered
    # in Thread-1,wait 01 finished
    # 5
    # in Thread-1,notify 01 is triggered
    # in Thread-1,wait 01 is triggered
    # in Thread-2,wait 02 finished
    # 6
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is triggered
    # in Thread-1,wait 01 finished

# +++++++++++++++++++++++++++++++++++++++++
#对于tar04和tar05的情况:假如两个Condition函数运行的总次数是奇数,比如:
if 1 == 1:
    pass
    # tar04执行for循环的次数为3次,for i range(1,6,2) 循环打印的是1,3,5
    # tar05执行for循环的次数为2次,for i range(2,6,2) 循环打印的是2,4
    # 那么tar04写成先wait再notify,tar05写成先notify再wait的话,线程2可以结束,但是线程1无法结束。
    # 因为tar05少了一个wait来通知tar04继续运行notify
    # 程序的运行结果如下:
    # press Enter to go mod A,else: press other key:  p
    # Thread-1 is started
    # 1
    # in Thread-1,wait 01 is triggered
    # Thread-2 is started
    # 2
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is riggered
    # in Thread-1,wait 01 finished
    # in Thread-1,notify 04 is tgriggered
    # in Thread-1,notify 04 finished
    # 3
    # in Thread-1,wait 01 is triggered
    # in Thread-2,wait 02 finished
    # 4
    # in Thread-2,notify 02 is triggered
    # in Thread-2,wait 02 is riggered
    # in Thread-1,wait 01 finished
    # in Thread-1,notify 04 is tgriggered
    # in Thread-1,notify 04 finished
    # 5
    # in Thread-1,wait 01 is triggered
    # in Thread-2,wait 02 finished

# ++++++++++++++++++++++
# 无论两个Condition函数执行for循环的次数为奇数还是偶数,都不能写成先同时先notify再wait的形式。
if 1 == 1:
    pass
    # 假如把tar04和tar05都写成先nofity再wait的样子,两个线程依然会交替运行,
    # 但是就会导致在最后一个循环时线程1已经由于notify而结束,但是没有wait来触发tar05继续执行tar05的nofity
    # 所以 tar05会一直hang在那里
    # 结果如下:
    # press Enter to go mod A, else: press other key: p
    # Thread - 1 is started
    # 1
    # in Thread - 1, notify 01 is triggered
    # in Thread - 1, wait 01 is triggered
    # Thread - 2 is started
    # 2
    # in Thread - 2, notify 02 is triggered
    # in Thread - 2, wait 02 is riggered
    # in Thread - 1, wait 01 finished
    # 3
    # in Thread - 1, notify 01 is triggered
    # in Thread - 1, wait 01 is triggered
    # in Thread - 2, wait 02 finished
    # 4
    # in Thread - 2, notify 02 is triggered
    # in Thread - 2, wait 02 is riggered
    # in Thread - 1, wait 01 finished
    # 5
    # in Thread - 1, notify 01 is triggered
    # in Thread - 1, wait 01 is triggered
    # in Thread - 2, wait 02 finished
    # 6
    # in Thread - 2, notify 02 is triggered
    # in Thread - 2, wait 02 is riggered
    # in Thread - 1, wait 01 finished

# +++++++++++++++++++
# 关于Condition
if 1 == 1:
    pass
    # 当你在程序的末尾启动# print('+++++++++++++++finished+++++++++++++++')时,会看到下面的情况。
    # 也就是说,以Condition控制的多线程,不会导致程序在多线程执行完毕之前被阻塞,
    # 所以,当你Condition多线程后面还有代码需要使用Condition多线程的结果时,你要特别留意这个问题。
    # 结果如下
    # Thread-1 is started
    # 1
    # +++++++++++++++finished+++++++++++++++
    # 后面的结果省略