首页 > 编程语言 > 详细

python 多线程和锁

时间:2019-12-01 17:13:35      阅读:96      评论:0      收藏:0      [点我收藏+]

1. 多线程的基本使用

import threading
import time

def run(num):
    print(Num: %s% num)
    time.sleep(3)

    if num == 4:
        print(Thread is finished.)
# 对函数 run 创建5个线程
for i in range(5): # 创建线程,target:目标函数,args:函数的参数,使用元组的形式 t = threading.Thread(target=run,args=(i,)) # 开始线程活动 t.start() time.sleep(0.01) print(Main thread is finished.)
结果:
Num: 0 Num:
1 Num: 2 Num: 3 Num: 4 Main thread is finished. Thread is finished.

# 上面打印的顺序是先打印
Main thread is finished.因为主线程已经完成了,而子线程里 slee(3),所以此时子线程尚未完成,大约3秒后,才打印的 Thread is finished.

2. 等待子线程执行:join

import threading
import time

def run(num):
    print(Num: %s% num)
    time.sleep(3)

    if num == 4:
        print(Thread is finished.)

Tlist = []
for i in range(5):
    # 创建线程,target:目标函数,args:函数的参数,使用元组的形式
    t = threading.Thread(target=run,args=(i,))
    # 开始线程活动
    t.start()
    Tlist.append(t)

for t in Tlist:  # 针对每个子线程,等待子线程执行一段时间,再继续往下执行主线程。
    # t.join(0.1)  # 针对每个子线程,等待0.1秒,继续执行主线程
    t.join()   # 没写时间,则默认等待子线程执行完毕,才继续往下执行主线程。

time.sleep(0.01)
print(Main thread is finished.)
结果:
Num: 0
Num: 1
Num: 2
Num: 3
Num: 4
Thread is finished.
Main thread is finished.

# 子线程使用了join方法,等待子线程执行完毕才继续执行主线程,所以打印顺序是正常的。

3. 守护线程

即只要主线程执行完毕,不管子线程状态如何,都会被强制杀掉。

import threading
import time

def run(num):
    print(Num: %s% num)
    time.sleep(3)

    if num == 4:
        print(Thread is finished.)

Tlist = []
for i in range(5):
    # 创建线程,target:目标函数,args:函数的参数,使用元组的形式
    t = threading.Thread(target=run,args=(i,))
    # 设置为守护线程
    t.setDaemon(True)
    # 开始线程活动
    t.start()
    Tlist.append(t)

for t in Tlist:  # 针对每个子线程,等待子线程执行一段时间,再继续往下执行主线程。
    t.join(0.1)  # 对子线程等待0.1秒后,继续执行主线程
    # t.join()   # 没写时间,则默认等待子线程执行完毕,才继续往下执行主线程。

time.sleep(0.01)
print(Main thread is finished.)
print(‘Current Thread:‘,threading.activeCount()) # 打印当前活动线程数量,这是主线程最后一个语句,所以不管此时还有多少个活动的守护线程,当此句执行完毕,守护线程都会被杀掉。
结果:
Num: 0 Num:
1 Num: 2 Num: 3 Num: 4 Main thread is finished. Current Thread: 6

# 少打印了 Thread is finished. 因为 主线程结束后,子线程就被杀掉了。

4. 线程锁

GIL锁:  Global Interpreter Lock,全局解释器锁。为了解决多线程之间数据完整性和状态同步的问题,在任意时刻只有一个线程在解释器中运行。这是CPython中的问题。

线程安全:在多线程中,共享的数据同一时间只能由一个线程执行。

互斥锁:(threading.Lock) 并不关心当前是哪个线程占有了该锁;如果该锁已经被占有了,那么任何其它尝试获取该锁的线程都会被阻塞,包括已经占有该锁的线程也会被阻塞。

递归锁:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源(已经占用该锁的线程,可以多次actuire,并不会阻塞)

死锁:死锁就是当一个线程已经占用了锁并且尚未释放,但是又有新的获取该锁的请求,亦或着两个线程分别占据着对方想要获取的锁,此时线程进入了阻塞的状态,就是死锁。

部份转自:https://www.jb51.net/article/74426.htm

部份转自:https://www.cnblogs.com/ArsenalfanInECNU/p/10022740.html

e.g.

互斥锁:threading.Lock

import threading

class MyThread(threading.Thread):
    def run(self):  # 这是重写的父类的run方法
        global num
        if mutex.acquire():  # 判断能否加锁,acquire()返回的是加锁的状态,加锁成功就是True
            num = num+1
            msg = self.name+ set num to +str(num)
            print(msg)
            # mutex.acquire()   # 这两句话如果不注释掉,就会进入死锁的状态。因为上一个锁还未释放,再次请求加锁,就会阻塞。
            # mutex.release()
            mutex.release()  # 释放锁
num = 0
mutex = threading.Lock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == __main__:
    test()

 

普通方法:

import threading
import time

def run(n):
    global num
    if mutex.acquire(): # 返回获取锁的结果,加锁成功为True,失败false
        num = num+1
        msg =Thread-%s set num to  %n + str(num)
        print(msg)
        mutex.release()
        time.sleep(2)

num = 0
mutex = threading.Lock()

for i in range(5):
    t = threading.Thread(target=run,args=(i+1,))
    t.start()

递归锁:threading.RLock

import threading

class MyThread(threading.Thread):
    def run(self):
        global num
        if mutex.acquire():
            num = num+1
            msg = self.name+ set num to +str(num)
            print(msg)
            mutex.acquire()  # 虽然再次acquire,但是并不会阻塞
            mutex.release()
            mutex.release()
num = 0
mutex = threading.RLock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == __main__:
    test()

 5. 信号量 semaphore

信号量用于限制同时运行的线程数量

import threading
import time

def run(n):
    sema.acquire()
    print(Thread: %s %n)
    time.sleep(2)
    sema.release()
# 声明信号量,同时允许5个线程执行 sema
= threading.BoundedSemaphore(5) for i in range(20): t = threading.Thread(target=run,args=(i+1,)) t.start()

 6. 事件:Event

事件可以用于多个线程进行简单通讯,事件可以控制一个内部 flag,初始时是 False,通过 set 方法使其变成 True,clear 方法使其变成 False,flag 为 False 时 wait 方法会一直阻塞直到flag 为True。

import threading
import time

# 事件可以控制一个内部标志,通过set方法使其变成True,clear方法使其变成False,为False时wait方法会一直阻塞直到标志为True。
# 这个标志初始时是False

event = threading.Event()
# event.set()    # 设置flag为True
# event.clear()  # 设置flag为False
# event.wait()   # 一直等待(阻塞),直到有线程使用 set 方法将 flag 变成 True
# event.is_set() # 返回flag的值

def boss():
    print(Boss: 今天加班5秒钟)
    event.clear()   # 清除 flag,使其值变为 false
    time.sleep(5)
    print("Boss: 时间到了,大家回家吧")
    event.set()     # 设置 flag,使其值变为 True


def employee():
    while True:
        if event.is_set():     # 判断:如果 flag 为 True
            print(Employee: 回家了!)
            break
        else:
            print(Emplyee: 工作中,请勿打扰...)
            event.wait()      # 如果 flag 为 False,则使用 wait 方法一直等待,直到有线程将其设置为 True


# 创建两个线程,分别为boss和employee,让它们根据 event 进行简单的通讯 b
= threading.Thread(target=boss,) e = threading.Thread(target=employee,) b.start() e.start()
结果:
Boss: 今天加班5秒钟 Emplyee: 工作中,请勿打扰... Boss: 时间到了,大家回家吧 Employee: 回家了!

 

 

 

 

python 多线程和锁

原文:https://www.cnblogs.com/wztshine/p/11965933.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!