欢迎来到 Kong Xiangqun 的博客

day6.线程-线程\守护线程\线程中安全问题\Semaphore\死锁_互斥锁_递归锁\Event事件\

一、线程

"""
进程:资源分配的最小单位
线程:cpu执行程序的最小单位
"""

1、一个进程资源中可以包含多个线程

from threading import Thread
from multiprocessing import Process
import os, time, random


def func(num):
    time.sleep(random.uniform(0.1,1))
    print("当前进程{},参数是{}".format(os.getpid(),num))


for i in range(10):
    t = Thread(target=func,args=(i,))
    t.start()

print(os.getpid())
# 结果
"""
20288
当前进程20288,参数是0
当前进程20288,参数是7
当前进程20288,参数是5
当前进程20288,参数是9
当前进程20288,参数是4
当前进程20288,参数是3
当前进程20288,参数是8
当前进程20288,参数是1
当前进程20288,参数是6
当前进程20288,参数是2

进程已结束,退出代码 0
"""
结果

2、并发的多线程和多进程谁的速度快? 多线程!

from threading import Thread
from multiprocessing import Process
import os,time,random
def func(num):
    print("当前进程{},参数是{}".format(os.getpid(), num))


if __name__ == "__main__":

    # 多线程
    lst = []
    # 记录开始时间
    startime = time.time()
    for i in range(1000):
        t = Thread(target=func,args=(i,))
        t.start()
        lst.append(t)

    # 等到所有的子线程执行完毕
    for i in lst:
        i.join()

    # 计算结束时间
    endtime = time.time()
    print("多线程执行时间",(endtime - startime))
多线程
# 多线程执行时间 0.1975560188293457
from threading import Thread
from multiprocessing import Process
import os,time,random
def func(num):
    print("当前进程{},参数是{}".format(os.getpid(), num))


if __name__ == "__main__":
    # 多进程
    lst = []
    # 记录开始时间
    startime = time.time()
    for i in range(100):
        t = Process(target=func,args=(i,))
        t.start()
        lst.append(t)

    # 等到所有的子线程执行完毕
    for i in lst:
        i.join()

    # 计算结束时间
    endtime = time.time()
    print("多进程执行时间",(endtime - startime))
多进程
# 多进程执行时间 3.8528594970703125

3、多线程之间,共享同一份进程资源

num = 1000
def func():
    global num
    num -= 1
    
for i in range(1000):
    t = Thread(target=func)
    t.start()
    
print(num)

二、用类定义线程

from threading import Thread
import os
import time

class MyThread(Thread):
    def __init__(self,name):
        # 手动调用父类的构造方法
        super().__init__()
        self.name = name
        
    def run(self):
        time.sleep(1)
        print("当前进程号码是{},名字是{}".format(os.getpid() , self.name))


if __name__ == "__main__":
    t = MyThread("当前是一个线程")
    t.start()
    print("主线程执行结束 ... ")
"""
主线程执行结束 ... 
当前进程号码是1164,名字是当前是一个线程

进程已结束,退出代码 0
"""
结果

1、线程相关函数

"""
线程.is_alive()    检测线程是否仍然存在
线程.setName()     设置线程名字
线程.getName()     获取线程名字
1.currentThread().ident 查看线程id号 
2.enumerate()        返回目前正在运行的线程列表
3.activeCount()      返回目前正在运行的线程数量
"""
from threading import Thread
import os
import time

def func():
    time.sleep(1)


if __name__ == "__main__":
    t = Thread(target=func)
    t.start()
    # 检测线程是否仍然存在
    print(t.is_alive())
    # 获取线程名字
    print(t.getName())  # Thread-1
    # 设置线程名字
    t.setName("xboyww")
    # 获取线程名字
    print(t.getName())
is_alive()\setName()\getName()
"""
True
Thread-1
xboyww

进程已结束,退出代码 0
"""
结果

 

from threading import Thread
from threading import currentThread

# 1.currentThread().ident 查看线程id号

def func():
    print("子线程的线程id{}".format(currentThread().ident))

if __name__ == "__main__":
    Thread(target=func).start()
    print("主线程的线程id{}".format(currentThread().ident))
currentThread
子线程的线程id13700
主线程的线程id17624

进程已结束,退出代码 0
结果

 

from threading import Thread
from threading import currentThread
import time

# 2.enumerate()        返回目前正在运行的线程列表
# 3.activeCount()      返回目前正在运行的线程数量 (了解)
from threading import enumerate
from threading import activeCount


def func():
    print("子线程的线程id{}".format(currentThread().ident))
    time.sleep(0.5)


if __name__ == "__main__":
    for i in range(10):
        Thread(target=func).start()
    lst = enumerate()
    # 主线程 + 10个子线程
    print(lst, len(lst))

    # 3.activeCount() 返回目前正在运行的线程数量
    print(activeCount())  # 11
enumerate\activeCount
"""
子线程的线程id21472
子线程的线程id22312
子线程的线程id14868
子线程的线程id21840
子线程的线程id15488
子线程的线程id11712
子线程的线程id21296
子线程的线程id6160
子线程的线程id9088
子线程的线程id21272[<_MainThread(MainThread, started 11784)>, <Thread(Thread-1, started 21472)>, <Thread(Thread-2, started 22312)>, <Thread(Thread-3, started 14868)>, <Thread(Thread-4, started 21840)>, <Thread(Thread-5, started 15488)>, <Thread(Thread-6, started 11712)>, <Thread(Thread-7, started 21296)>, <Thread(Thread-8, started 6160)>, <Thread(Thread-9, started 9088)>, <Thread(Thread-10, started 21272)>]
 11
11

进程已结束,退出代码 0
"""
结果

三、守护线程

# 守护线程 : 等待所有线程全部执行完毕之后,自己在终止,守护所有线程
from threading import Thread
import time
def func1():
    while True:
        time.sleep(0.5)
        print("我是func1")

def func2():
    print("我是func2 start ... ")
    time.sleep(3)
    print("我是func2 end ... ")

def func3():
    print("我是func3 start ... ")
    time.sleep(5)
    print("我是func3 end ... ")

if __name__ == "__main__":
    t1 = Thread(target=func1)
    t2 = Thread(target=func2)
    t3 = Thread(target=func3)
    
    # 在start调用之前,设置线程为守护线程
    t1.setDaemon(True)
    
    t1.start()
    t2.start()
    t3.start()
    
    print("主线程执行结束 .... ")

四、线程中安全问题

from threading import Thread
import time
def func1():
    while True:
        time.sleep(0.5)
        print("我是func1")

def func2():
    print("我是func2 start ... ")
    time.sleep(3)
    print("我是func2 end ... ")

def func3():
    print("我是func3 start ... ")
    time.sleep(5)
    print("我是func3 end ... ")

if __name__ == "__main__":
    t1 = Thread(target=func1)
    t2 = Thread(target=func2)
    t3 = Thread(target=func3)
    
    # 在start调用之前,设置线程为守护线程
    t1.setDaemon(True)
    
    t1.start()
    t2.start()
    t3.start()
    
    print("主线程执行结束 .... ")
线程中安全问题 Lock

五、Semaphore 信号量

from threading import Semaphore , Thread
import time
def func(i,sm):
    # 上锁 + 解锁
    with sm:
        print(i)
        time.sleep(3)    
if __name__ == "__main__":
    # 支持同一时间,5个线程上锁
    sm = Semaphore(5)
    for i in range(20):
        Thread(target=func,args=(i,sm)).start()
    
"""
再创建线程的时候是异步创建
在执行任务时,遇到Semaphore进行上锁,会变成同步程序
"""

六、死锁_互斥锁_递归锁

1、语法上的死锁

"""只上锁不解锁是死锁"""
from threading import Lock,Thread,RLock
import time

lock = Lock()
lock.acquire()
lock.acquire()
lock.acquire()

lock.release()
print(1)

2、逻辑上的死锁

from threading import Lock,Thread,RLock
import time

noodle_lock = Lock()
kuaizi_lock = Lock()


def eat1(name):
    noodle_lock.acquire()
    print("%s 抢到面条了" % (name))
    kuaizi_lock.acquire()
    print("%s 抢到筷子了" % (name))

    print("开始享受面条 ... ")
    time.sleep(0.5)

    kuaizi_lock.release()
    print("%s 放下筷子" % (name))
    noodle_lock.release()
    print("%s 放下面条" % (name))


def eat2(name):
    kuaizi_lock.acquire()
    print("%s 抢到筷子了" % (name))
    noodle_lock.acquire()
    print("%s 抢到面条了" % (name))

    print("开始享受面条 ... ")
    time.sleep(0.5)

    noodle_lock.release()
    print("%s 放下面条" % (name))
    kuaizi_lock.release()
    print("%s 放下筷子" % (name))


if __name__ == "__main__":
    name_lst1 = ["aaa", "bbb"]
    name_lst2 = ["ccc", "ddd"]

    for name in name_lst1:
        Thread(target=eat1, args=(name,)).start()

    for name in name_lst2:
        Thread(target=eat2, args=(name,)).start()
逻辑上的死锁
"""
aaa 抢到面条了
aaa 抢到筷子了
开始享受面条 ... 
aaa 放下筷子
ccc 抢到筷子了
aaa 放下面条bbb 抢到面条了
"""
结果

3、递归锁的使用

1、基本

# 递归锁专门用来解决这种死锁现象
# 临时用于快速解决线上项目发生阻塞死锁问题的
from threading import Lock,Thread,RLock

rlock = RLock()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
print(112233)
rlock.release()
rlock.release()
rlock.release()
rlock.release()

print("程序结束 ... ")
"""
112233
程序结束 ... 

进程已结束,退出代码 0
"""
结果

2、用递归锁解决死锁现象

# 递归锁专门用来解决这种死锁现象
# 临时用于快速解决线上项目发生阻塞死锁问题的
from threading import Lock,Thread,RLock
import time
noodle_lock = kuaizi_lock = RLock()


def eat1(name):
    noodle_lock.acquire()
    print("%s 抢到面条了" % (name))
    kuaizi_lock.acquire()
    print("%s 抢到筷子了" % (name))

    print("开始享受面条 ... ")
    time.sleep(0.5)

    kuaizi_lock.release()
    print("%s 放下筷子" % (name))
    noodle_lock.release()
    print("%s 放下面条" % (name))


def eat2(name):
    kuaizi_lock.acquire()
    print("%s 抢到筷子了" % (name))
    noodle_lock.acquire()
    print("%s 抢到面条了" % (name))

    print("开始享受面条 ... ")
    time.sleep(0.5)

    noodle_lock.release()
    print("%s 放下面条" % (name))
    kuaizi_lock.release()
    print("%s 放下筷子" % (name))


if __name__ == "__main__":
    name_lst1 = ["宋云杰", "高云杰"]
    name_lst2 = ["王浩", "孙志心"]

    for name in name_lst1:
        Thread(target=eat1, args=(name,)).start()

    for name in name_lst2:
        Thread(target=eat2, args=(name,)).start()
解决死锁
"""
宋云杰 抢到面条了
宋云杰 抢到筷子了
开始享受面条 ... 
宋云杰 放下筷子
宋云杰 放下面条
高云杰 抢到面条了
高云杰 抢到筷子了
开始享受面条 ... 
高云杰 放下筷子
高云杰 放下面条
王浩 抢到筷子了
王浩 抢到面条了
开始享受面条 ... 
王浩 放下面条
王浩 放下筷子
孙志心 抢到筷子了
孙志心 抢到面条了
开始享受面条 ... 
孙志心 放下面条
孙志心 放下筷子

进程已结束,退出代码 0
"""
结果

4、互斥锁(尽量用一把锁解决问题)

mylock = Lock()
def eat1(name):
    mylock.acquire()
    print("%s 抢到面条了" % (name))
    print("%s 抢到筷子了" % (name))
    
    print("开始享受面条 ... ")
    time.sleep(0.5)    

    print("%s 放下筷子" % (name))
    print("%s 放下面条" % (name))
    mylock.release()

def eat2(name):
    mylock.acquire()
    print("%s 抢到筷子了" % (name))
    print("%s 抢到面条了" % (name))
    
    print("开始享受面条 ... ")
    time.sleep(0.5)    

    print("%s 放下面条" % (name))    
    print("%s 放下筷子" % (name))
    mylock.release()

if __name__ == "__main__":
    
    name_lst1 = ["宋云杰","高云杰"]
    name_lst2 = ["王浩","孙志心"]
    
    for name in name_lst1:
        Thread(target=eat1,args=(name,)).start()
        
    for name in name_lst2:
        Thread(target=eat2,args=(name,)).start()
互斥锁

七、Event事件

"""
    e = Event()
    # wait   动态添加阻塞
    # clear  将内部的阻塞值改成False
    # set    将内部的阻塞值改成True
    # is_set 获取内部的阻塞值状态(True False)
"""

1、基本语法

from threading import Event

e = Event()
print(e.is_set())
e.set()
print(e.is_set())
e.clear()
print(e.is_set())
# 代表最多阻塞3秒
e.wait(3)
print("程序运行中... ")
"""
False
True
False
程序运行中... 

进程已结束,退出代码 0
"""
结果

2、模拟链接远程数据库

from threading import Event,Thread
import time,random

def check(e):
    # 用一些延迟来模拟检测的过程
    time.sleep(random.randrange(1,6)) # 1 2 3 4 5
    # time.sleep(1)
    print("开始检测链接用户的合法性")
    e.set()
    
    
def connect(e):
    sign = False
    for i in range(1,4): # 1 2 3    
        # 设置最大等待1秒
        e.wait(1)    
    
        if e.is_set():
            print("数据库链接成功 ... ")
            sign = True
            break
        else:
            print("尝试链接数据库第%s次失败 ... " % (i))
            
    if sign == False:
        # 主动抛出异常,(超时异常)
        raise TimeoutError
        
e = Event()
# 线程1号负责执行连接任务
Thread(target=connect,args=(e,)).start()

# 线程2号负责执行检测任务
Thread(target=check,args=(e,)).start()
链接远程数据库
"""
尝试链接数据库第1次失败 ... 
尝试链接数据库第2次失败 ... 
开始检测链接用户的合法性
数据库链接成功 ... 

进程已结束,退出代码 0
"""
结果

 

posted @ 2020-08-23 13:24  kongxiangqun20220317  阅读(134)  评论(0)    收藏  举报