python的threading的使用(join方法,多线程,锁threading.Lock和threading.Condition

一、开启多线程方法一

import threading,time

def write1():
    for i in range(1,5):
        print('1')
        time.sleep(1)


def write12():
    for i in range(1, 5):
        print('2')
        time.sleep(1)

# 给两个函数开一个线程,target后面赋值函数名
t1 = threading.Thread(target=write1)
t2 = threading.Thread(target=write12)
# 使用start函数启动这个线程
t1.start()
t2.start()
# 输出线程数量
print(threading.enumerate())
'''
输出:
1
2
[<_MainThread(MainThread, started 21440)>, <Thread(Thread-1, started 2344)>, <Thread(Thread-2, started 3016)>]
1
2
2
1
2
1
'''

二、开启多线程方法二

import threading,time

class Write1Threaq(threading.Thread):
    def run(self):
        for i in range(1, 5):
            print('1----%s',threading.current_thread())
            time.sleep(1)

class Write2Threaq(threading.Thread):
    def run(self):
        for i in range(1, 5):
            # 输出当前线程的名称
            print('2----%s',threading.current_thread())
            time.sleep(1)

def main():
    # 继承自threading.Thread之后,只需要实现run方法,执行start函数后,会自动执行run函数
    t1 = Write1Threaq()
    t2 = Write2Threaq()
    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

'''
输出:
1----%s <Write1Threaq(Thread-1, started 6304)>
2----%s <Write2Threaq(Thread-2, started 10524)>
2----%s <Write2Threaq(Thread-2, started 10524)>
1----%s <Write1Threaq(Thread-1, started 6304)>
2----%s <Write2Threaq(Thread-2, started 10524)>
1----%s <Write1Threaq(Thread-1, started 6304)>
1----%s2----%s  <Write2Threaq(Thread-2, started 10524)>
<Write1Threaq(Thread-1, started 6304)>

'''

三、不上锁会出现的错误情况

import time,threading

value = 0
def write():
    global value
    for i in range(1,1000000):
        value+=1
    print(value)

def main():
    for i in range(1,3):
        t1 = threading.Thread(target=write)
        t1.start()

if __name__ == '__main__':
    main()

'''
输出:
# 输出结果显然不符合我们的预期,例如value等于10的时候,两个线程同时进行了两次value+1,但是这个时候两个value+1的
# value都是10,那么结果value就是11,可以说少加了一次1
1143699
1227119
'''

四、使用Lock进行上锁解决三的问题

import time,threading
# 使用多线程锁
glock = threading.Lock()

value = 0
def write():
    global value
    # 上锁
    glock.acquire()
    for i in range(1,1000000):
        value+=1
    # 解锁
    glock.release()
    print(value)

def main():
    for i in range(1,3):
        t1 = threading.Thread(target=write)
        t1.start()

if __name__ == '__main__':
    main()

'''
输出:这样就没问题了
999999
1999998
'''

五、condition的使用

threading.Condition 是一个继承自threading.Lock的一个类,所以它也有上锁解锁的功能,上锁acquire,解锁ralease
同时它还具有wait()函数,其功能为将程序在此处阻塞,可以通过函数notify,或者notify_all来进行唤醒,这两个函数要在release之前调用
notify执行一次只会唤醒一个线程,默认是第一个等待的线程
notify_all执行一次会唤醒所有的线程,
import random,threading,time

gcondition = threading.Condition()
Money = 0
def Create():
global Money
num=0
while 1:
if num>10:
break
gcondition.acquire()
Money += random.randint(1,100)
print('生产Money:',Money)
gcondition.notify_all()
gcondition.release()
num+=1
time.sleep(1)

def Consumer(money):
global Money
num = 0
while 1:
if num>2:
break
gcondition.acquire()
while Money<money:
print('金额不足!')
time.sleep(1)
gcondition.wait()
Money-=money
print('总钱数:%s,花费:%s,剩余:%s。',Money+money,money,Money)
gcondition.release()
num+=1
time.sleep(1)


def main():
for i in range(1, 3):
t1 = threading.Thread(target=Create)
t1.start()
print('---------------------')
for i in range(1, 3):
ans = random.randint(1, 100)
t1 = threading.Thread(target=Consumer,args=[ans])# 注意这里的参数传递方式
t1.start()




if __name__ == '__main__':
main()
'''
生产Money: 18
生产Money: 90
---------------------
总钱数:%s,花费:%s,剩余:%s。 90 84 6
金额不足!
生产Money: 75
生产Money: 105
总钱数:%s,花费:%s,剩余:%s。 105 84 21
金额不足!
生产Money: 107
生产Money: 171
总钱数:%s,花费:%s,剩余:%s。 171 84 87
总钱数:%s,花费:%s,剩余:%s。 87 26 61
生产Money: 146
总钱数:%s,花费:%s,剩余:%s。 146 26 120
生产Money: 181
生产Money: 230
生产Money: 253
总钱数:%s,花费:%s,剩余:%s。 253 26 227
生产Money: 275
生产Money: 320
生产Money: 350
生产Money: 423
生产Money: 431
生产Money: 484
生产Money: 527
生产Money: 596
生产Money: 646
生产Money: 721
生产Money: 788
生产Money: 850
'''

Thread参数传递的问题

 错误的参数传递

threading.Thread(target=Consumer(ans))
import random,threading,time

gcondition = threading.Condition()
Money = 100
def Create():
    global Money
    num=0
    while 1:
        if num>10:
            break
        gcondition.acquire()
        Money += random.randint(1,100)
        print('生产Money:',Money)
        gcondition.notify_all()
        gcondition.release()
        num+=1
        time.sleep(1)

def Consumer(money):
    global Money
    num = 0
    while 1:
        if num>2:
            break
        gcondition.acquire()
        while Money<money:
            print('金额不足!')
            time.sleep(1)
            gcondition.wait()
        Money-=money
        print('总钱数:%s,花费:%s,剩余:%s。',Money+money,money,Money)
        gcondition.release()
        num+=1
        time.sleep(1)


def main():
    for i in range(1, 3):
        print('222')
        ans = random.randint(1, 100)
        t1 = threading.Thread(target=Consumer(ans))
        t1.start()
    print('---------------------')

    for i in range(1, 3):
        t1 = threading.Thread(target=Create)
        t1.start()



if __name__ == '__main__':
    main()

'''
222
总钱数:%s,花费:%s,剩余:%s。 100 12 88
总钱数:%s,花费:%s,剩余:%s。 88 12 76
总钱数:%s,花费:%s,剩余:%s。 76 12 64
222
总钱数:%s,花费:%s,剩余:%s。 64 57 7
金额不足!

程序将会一直卡到这里,这是因为你这样的参数传递方式相当于在start函数没有执行,函数就开始了运行
'''

 正确的参数传递

threading.Thread(target=Consumer,args=[ans])
import random,threading,time

gcondition = threading.Condition()
Money = 100
def Create():
    global Money
    num=0
    while 1:
        if num>10:
            break
        gcondition.acquire()
        Money += random.randint(1,100)
        print('生产Money:',Money)
        gcondition.notify_all()
        gcondition.release()
        num+=1
        time.sleep(1)

def Consumer(money):
    global Money
    num = 0
    while 1:
        if num>2:
            break
        gcondition.acquire()
        while Money<money:
            print('金额不足!')
            time.sleep(1)
            gcondition.wait()
        Money-=money
        print('总钱数:%s,花费:%s,剩余:%s。',Money+money,money,Money)
        gcondition.release()
        num+=1
        time.sleep(1)


def main():
    the_list = []
    for i in range(1, 3):
        ans = random.randint(1, 100)
        # 参数传递要这样,可不能写成Thread(target=Consumer(ans))
        t1 = threading.Thread(target=Consumer,args=[ans])
        #the_list.append(t1)
        t1.start()
    for i in the_list:
        i.start()
    print('---------------------')

    for i in range(1, 3):
        t1 = threading.Thread(target=Create)
        t1.start()



if __name__ == '__main__':
    main()

'''
总钱数:%s,花费:%s,剩余:%s。 222
100 10 90
总钱数:%s,花费:%s,剩余:%s。 90 17 ---------------------
73
生产Money: 99
生产Money: 141
生产Money: 162
总钱数:%s,花费:%s,剩余:%s。 162 17 145
总钱数:%s,花费:%s,剩余:%s。 145 10 135
生产Money: 164
生产Money: 228
总钱数:%s,花费:%s,剩余:%s。 228 17 211
总钱数:%s,花费:%s,剩余:%s。 211 10 201
生产Money: 203
生产Money: 249
生产Money: 276
生产Money: 321
生产Money: 342
生产Money: 387
生产Money: 475
生产Money: 501
生产Money: 596
生产Money: 682
生产Money: 731
生产Money: 823
生产Money: 888
生产Money: 975
生产Money: 1025
生产Money: 1056
生产Money: 1129
'''

六、join函数

如果一个线程在执行过程中要调用另外一个线程,并且等到其完成以后才能接着执行,解决方法就是“那么在调用这个线程时可以使用被调用线程的join方法。”

下面先说一下setDeamon()吧:
其实主线程并不会结束setDeamon(True)的线程,而是当主线程执行完毕之后不会再去关注setDeamon(True)的线程。
所以setDeamon(True)的线程的结果是我们无法获取到的,类似于爱咋咋地?不管你输出什么,我都不看,主线程跑
完就结束整个python process。
而setDeamon(False)的线程会一直受到主线程的关注,就算主线程跑完了也会等setDeamon(False)的线程跑完然后
再结束整个python process。
所以说,就算setDeamon(True)的线程在主线程之后跑完,但如果在setDeamon(False)的线程之前跑完的话,也是会
输出结果的,而不是被所谓的主线程结束就杀死setDeamon(False)的线程。

看一下不同setDeamon运行结果:

#coding:utf-8
import threading
import time

def action(arg):
    for i in range(2):
        print('sub thread start!the thread name is:%s    ' % threading.currentThread().getName())
        print('the arg is:%s   ' %arg)
        time.sleep(1)

for i in range(4):
    t =threading.Thread(target=action,args=(i,))
    t.setDaemon(True)
    t.start()

print('main_thread end!')

'''
setDaemon(True)的输出:
sub thread start!the thread name is:Thread-1    
the arg is:0   
sub thread start!the thread name is:Thread-2    
the arg is:1   
sub thread start!the thread name is:Thread-3    
the arg is:2   
sub thread start!the thread name is:Thread-4    
the arg is:3   
main_thread end!
'''
'''
setDaemon(False)的输出:
sub thread start!the thread name is:Thread-1    
the arg is:0   
sub thread start!the thread name is:Thread-2    
the arg is:1   
sub thread start!the thread name is:Thread-3    
the arg is:2   
sub thread start!the thread name is:Thread-4    
the arg is:3   
main_thread end!
sub thread start!the thread name is:Thread-2    sub thread start!the thread name is:Thread-1    
the arg is:0   

the arg is:1   
sub thread start!the thread name is:Thread-3    
the arg is:2   
sub thread start!the thread name is:Thread-4    
the arg is:3   
'''

join使用的程序正确书写方法:

#coding:utf-8
import threading
import time

def action(arg):
    time.sleep(1)
    print('sub thread start!the thread name is:%s    ' % threading.currentThread().getName())
    print('the arg is:%s   ' %arg)
    time.sleep(1)

#不正确写法,会导致多线程顺序执行,失去了多线程的意义
for i in range(4):
    t =threading.Thread(target=action,args=(i,))
    t.setDaemon(True)
    t.start()
    t.join()

#正确写法
thread_list = []    #线程存放列表
for i in range(4):
    t =threading.Thread(target=action,args=(i,))
    t.setDaemon(True)
    thread_list.append(t)

for t in thread_list:
    t.start()

for t in thread_list:
    t.join()
print('main_thread end!')
原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13432359.html