欢迎来到十九分快乐的博客

生死看淡,不服就干。

6.线程

线程

1.线程

# 线程
"""
进程是系统资源分配的最小单位
线程是计算机中调调的最小单位
一个进程里至少一个主线程
"""
from threading import Thread
from multiprocessing import Process
import time,random,os

# 1.多个线程是异步并发操作
def func(i):
    time.sleep(random.random())
    print(i,os.getpid())

if __name__ == "__main__":
    for i in range(10):
        t = Thread(target=func,args = (i,)) # 创建线程对象
        t.start() 
    print(os.getpid())

# 2.多线程之间的数据彼此共享
num = 1000
lst = []
def func():
    global num
    num -= 1
for i in range(1000):
    t = Thread(target = func)
    t.start()
    lst.append(t)
for i in lst:
    i.join()
print(num) # 0

2.自定义线程

# 1. 自定义线程
from threading import Thread,enumerate
import os,time

class My(Thread): # 必须继承Thread
    def __init__(self,name):
        super().__init__() #必须手动调用父类构造方法,才能添加成员
        self.name = name

    def run(self):
        print("当前进程号{},参数{}".format(os.getpid(),self.name))

if __name__ == "__main__":
    t = My("好人")
    t.start()
    t.join()
    print("主进程执行结束...")

# 2.线程相关属性
"""
线程.is_alive()    检测线程是否仍然存在
线程.setName()     设置线程名字
线程.getName()     获取线程名字
1.currentThread().ident 查看线程id号 
2.enumerate()        返回目前正在运行的线程列表
3.activeCount()      返回目前正在运行的线程数量
"""
from threading import currentThread as ct
from threading import enumerate ,Thread
import time
def func():
    time.sleep(1)
    print("当前线程号{}".format(ct().ident))
    
if __name__ == "__main__":
    t = Thread(target = func)
    t.start()
    lst = enumerate() #线程对象列表
    print(lst,len(lst))
    res = t.is_alive()
    print(res) # True
    print(t.getName()) #Thread-1
    t.setName("下载线程") 
    print(t.getName()) # 下载线程

# 3.线程的缺陷
"""
GIL: 
    全局解释器锁
效果: 
    同一时间,一个进程下的多个线程只能被一个cpu执行,不能实现线程的并行操作 
原因: 
    1.历史原因
    2.python是解释型语言
改善方法:
    1.用多进程间接实现线程的并行
    2.换一个Pypy,Jpython解释器
	
目前来看,还不能根本解决;
对于io密集型任务,python 绰绰有余.
"""

3.守护线程

# 守护线程
"""
等待所有线程全部执行结束,终止守护线程,守护所有线程
语法:
    线程.setDaemon(True) 
"""
from threading import Thread
import time

def func1():
    while True:
        time.sleep(1)
        print(111)
def func2():
    time.sleep(3)
    print(222)

if __name__ == "__main__":
    t1 = Thread(target = func1)
    t2 = Thread(target = func2)
    t1.setDaemon(True) # 设置守护线程
    t1.start()
    t2.start()
    t2.join()
    print("助计算")

4.线程互斥锁Lock 与 信号量Semaphore

# 1.线程数据安全锁 Lock
from threading import Thread,Lock
import time

total = 0
def func1(lock):
    global total
    lock.acquire() # 加锁方式一
    for i in range(10000):
        total += 1
    lock.release() #解锁

def func2(lock):
    global total
    with lock: # 加锁方式二 : 自动完成加锁解锁
        for i in range(10000):
            total -= 1

if __name__ == "__main__":
    lst = []
    lock = Lock() # 创建锁对象
    for i in range(10):
        t1 = Thread(target = func1,args = (lock,))
        t1.start()
        t2 = Thread(target = func2,args = (lock,))
        t2.start()
        lst.append(t1)
        lst.append(t2)       
    for i in lst:
        i.join()
    print(total) # 0
    
# 2.Semaphore : 线程信号量
from threading import Semaphore ,Thread
import time,random

def func(i,sem):
    time.sleep(random.random())
    with sem: # 上锁
        print("{}唱歌".format(i))
        time.sleep(random.randrange(2,4))
        print("{}走了".format(i))

if __name__ == "__main__":
    sem = Semaphore(3) # 创建锁对象,同一时间给3个线程加锁
    for i in range(10):
        t = Thread(target=func,args=(i,sem))
        t.start()
    print("主线程结束`~")    

5.死锁Lock与递归锁RLock

from threading import Thread,Lock,RLock
import time
# 1.语法上死锁
"""
只上锁,不解锁,程序阻塞
"""
# 2.逻辑上的死锁
"""
两把不同的所同时上锁
"""
lock1 = Lock()
lock2 = Lock()
def eat1(name):
    lock1.acquire()
    print("{}抢到了面条~~".format(name))
    lock2.acquire()
    print("{}抢到了筷子~~".format(name))
    print("开始吃面条~~")
    time.sleep(1)
    lock2.release()
    print("{}放下了筷子~~".format(name))
    lock1.release()
    print("{}放下了面条~~".format(name))

def eat2(name):
    lock2.acquire()
    print("{}抢到了筷子~~".format(name))
    lock1.acquire()
    print("{}抢到了面条~~".format(name))
    print("开始吃面条~~")
    time.sleep(1)
    lock1.release()
    print("{}放下了面条~~".format(name))
    lock2.release()
    print("{}放下了筷子~~".format(name))
    
if __name__ == "__main__":
    lst1 = ["熊大","熊二"]
    lst2 = ["贾英贺","光头强"]
    for i in lst1:
        Thread(target =eat1,args = (i,)).start()
    for i in lst2:
        Thread(target =eat1,args = (i,)).start()

# 3.解决办法 
"""
解决办法一:
    递归锁 : 是专门解决死锁问题
    连续上锁形同虚设,可以快速开锁
解决办法二:
    尽量使用一把锁解决问题,不要使用嵌套锁,容易逻辑死锁
"""
# 基本语法
lock = RLock() # 创建递归锁
lock.acquire()
lock.acquire()
lock.release()
lock.release()
print(666)

6.事件Event

# 事件Event
"""
wait : 动态加阻塞
is_set : 获取内部成员属性值
clear : 把成员属性值舍尾False
set : 把成员属性值设为True
"""
from threading import Thread ,Event
import time,random

# 连接远程数据库
# 检测线路
def check(e):
    print("检测中~")
    time.sleep(1)
    print("检测账号中~")
    time.sleep(1)
    print("检测密码中~")
    time.sleep(random.randrange(1,4))
    e.set() # 检测OK,放行

# 连接线程
def connect(e):
    sign = False
    for i in range(1,4):
        e.wait(1) # 最多阻塞1秒
        if e.is_set():
            print("连接成功~~")
            sign = True
            break
        else:
            print("连接第{}失败~~".format(i))
     # 如果没成功,抛出超时异常       
    if sign ==False:
        raise TimeoutError
        
if __name__ == "__main__":
    e = Event() # 创建事件对象
    t = Thread(target=check,args = (e,)).start()
    t = Thread(target=connect,args = (e,)).start()

7.线程队列

# 线程队列
"""
put 存放数据 超出队列长度阻塞
get 获取数据 超出队列长度阻塞
put_nowait  存放数据 超出队列长度报错
get_nowait  获取数据  超出队列长度报错
"""
# 1.Queue 队列  : 先进先出,后进后出
from queue import Queue
q = Queue()
q.put(11)
q.put(22)
print(q.get())  #11
print(q.get())  #22
# print(q.get()) #程序阻塞,队列没有数据了

q = Queue(2) # 队列最多存放2个元素
q.put(1)
q.put(2)
# q.put(3) # 阻塞

# 2.LifoQueue 队列 : 先进后出,后进先出
from queue import LifoQueue
lq = LifoQueue()
lq.put(111)
lq.put(222)
print(lq.get()) # 222
print(lq.get()) # 111

# 3.PriorityQueue 队列
"""
按照优先级排序存放数据 (默认从小到大),获取数据从小到大
    可以对数字,字母,容器进行排序
注意:
    队列里面只能存放同一类型的数据,不能混杂其他类型数据
"""
from queue import PriorityQueue

# (1) 对数字排序
pq = PriorityQueue()
pq.put(22)
pq.put(11)
pq.put(33)
print(pq.get()) 
print(pq.get())
print(pq.get())

# (2)多个类型数据
"""
pq.put(11)
pq.put("aa")
# 错误 : '<' not supported between instances of 'str' and 'int'
"""
posted @ 2021-01-04 23:02  十九分快乐  阅读(34)  评论(0编辑  收藏  举报