41 thread类 锁 事件 信号量 条件 定时器

进程跟线程的执行效率对比

同样任务线程的执行效率

import time
from threading import Thread
from multiprocessing import Process
# def  func(a):
# a+=1
#
# if __name__ == '__main__':
# start=time.time()
# t1=[]
# for i in range(50):
# t=Thread(target=func,args=(i,)) #分出50个线程,来执行任务
# t.start() #任务开始
# t1.append(t) #
# for t in t1:
# t.join()
# print("主线程")
# print(time.time()-start)
# statr=time.time()

同样任务进程的执行效率

import time
from  threading  import Thread
from  multiprocessing  import  Process

def  func(a):
    a+=1

if __name__ == '__main__':
    start=time.time()
    t1=[]
    for i in range(50):
        p=Process(target=func,args=(i,))
        p.start()
        t1.append(p)
    for  t in t1:
        t.join()
    print("主进程")
    print(time.time() - start)
View Code

 # start     开始   join  等待
# terminate   强制停止一个进程     在线程中没有

 

线程之间的数据共享

from  threading import Thread
n=100
def  func():
    global n
    n=n-1
if __name__ == '__main__':
    t1=[]
    for i in range(100):
        t=Thread(target=func)
        t.start()
        t1.append(t)
    for  w  in  t1:
        t.join()
    print(n)
View Code

因为线程之间的数据是共享的,难免会造成数据混乱,所以用守护线程

import time
from threading import Thread
def a1():
    while 1:
        print(True)
        time.sleep(0.5)
def a2():
    print("in t2  start")
    time.sleep(3)
    print("in t2  end")
if __name__ == '__main__':
    t1=Thread(target=a1)
    t1.setDaemon(True)
    t1.start()
    t2 = Thread(target=a2)
    t2.start()
    time.sleep(1)
    print("主线程")
View Code

主线程如果结束了 那么整个进程就结束
守护线程 会等待主线程结束之后才结束.
     主进程 等待 守护进程 子进程
     守护进程 只守护主进程的代码就可以了
     守护线程不行 主线程如果结束了 那么整个进程就结束 所有的线程就都结束

from threading import Thread,get_ident
开启线程的第二种方式和查看线程id

from threading import Thread,get_ident

class MyThread(Thread):
    def __init__(self,args):
        super().__init__()
        self.args=args

    def run(self):
        print("in my thread:", get_ident(),self.args)

print("main",get_ident())
t=MyThread("wahaha") #主线程id
t.start()  #子线程 id
View Code

线程中的方法

Thread  开启一个线程

get_ident  获得线程的运行id

currentThread    给每个子线程一个名字 跟id

enumerate,  正在运行的线程

activeCount  正在运行的线程的数量 相当于len(enumerate())

import time
from threading import Thread,get_ident,currentThread,enumerate,activeCount
# 开启线程的第二种方式和查看线程id
class MyThread(Thread):
    def __init__(self,args):
        super().__init__()   # Thread类的init,在这个方法中做了很多对self的赋值操作,都是给创建线程或者使用线程的时候用的
        self.args = args

    def run(self):
        time.sleep(0.1)
        print(1)
        print(currentThread())
        print('in my thread : ',get_ident(),self.args)

print('main',get_ident())
t = MyThread('wahaha')
# print(t.is_alive())
t.start()
print(activeCount())  # 正在运行的线程的数量 len(enumerate())
# print(enumerate())
# print('t : ',t)
# print(t.is_alive())
View Code

# thread对象的其他方法 : isAlive ,setname,getname
# threading模块的方法 : currentTread,activeCount,enumerate   

   =======================精讲join==========

import time
from threading import Thread
from multiprocessing import Process

def func():
    for i in range(5):
        print('in thread')
        time.sleep(0.2)

if __name__ == '__main__':
    p_l = []
    for i in range(10):
        p = Process(target=func)
        p.start()
        p_l.append(p)
    p_l[0].join()   # 保证第0个进程结束了
    p_l[1].join()   # p1执行完了么?  执行完了就不阻塞
    p_l[2].join()   
    p_l[3].join()
    p_l[4].join()
    p_l[5].join()
    p_l[6].join()
    p_l[7].join()
    p_l[8].join()
    p_l[9].join()  # p9执行完了么 ?
        # p.join()   # 主进程被阻塞,等待p结束之后再继续往下执行
    for i in range(5):
        print('*'*10)
        time.sleep(0.2)
View Code

==================锁===========

在多个进程/线程同时访问一个数据的时候就会产生数据的不安全现象

多进程 访问文件

多线程 同时去访问一个数据

GIL 全局解释器锁

  在同一个进程里的每一个线程同一时间只能有一个线程访问cpu

尽量不要设置全局变量

只要在多线程/进程之间用到全局变量  就加上锁

from threading import Lock,Thread
lock = Lock()
lock.acquire()

noodle = 100
def func(name,lock):
    global noodle
    lock.acquire()
    noodle -= 1
    lock.release()
    print('%s吃到面了'%name)

if __name__ == '__main__':
    lock = Lock()  # 线程锁 互斥锁
    t_lst = []
    for i in range(10):
        t = Thread(target=func,args=(i,lock))
        t.start()
        t_lst.append(t)
    for t in t_lst:
        t.join()
    print(noodle)
View Code

经典的科学家吃面问题   死锁

import time
from threading import Thread,Lock
lock = Lock()
noodle_lock = Lock()
fork_lock = Lock()
def eat1(name):
    noodle_lock.acquire()
    print('%s拿到了面' % name)
    fork_lock.acquire()
    print('%s拿到了叉子' % name)
    print('%s在吃面'%name)
    time.sleep(0.5)
    fork_lock.release()  # 0.01
    noodle_lock.release() # 0.01   

def eat2(name):
    fork_lock.acquire()  # 0.01
    print('%s拿到了叉子' % name) # 0.01
    noodle_lock.acquire()
    print('%s拿到了面' % name)
    print('%s在吃面'%name)
    time.sleep(0.5)
    noodle_lock.release()
    fork_lock.release()

eat_lst = ['alex','wusir','太白','yuan']
for name in eat_lst:  # 8个子线程 7个线程 3个线程eat1,4个线程eat2
    Thread(target=eat1,args=(name,)).start()
    Thread(target=eat2,args=(name,)).start()
"""alex拿到了面
alex拿到了叉子
alex在吃面
alex拿到了叉子
wusir拿到了面    """
View Code

解决方案第一版

import time
from threading import Thread,Lock
lock = Lock()
def eat1(name):
    lock.acquire()
    print('%s拿到了面' % name)
    print('%s拿到了叉子' % name)
    print('%s在吃面'%name)
    time.sleep(0.5)
    lock.release() # 0.01

def eat2(name):
    lock.acquire()  # 0.01
    print('%s拿到了叉子' % name) # 0.01
    print('%s拿到了面' % name)
    print('%s在吃面'%name)
    time.sleep(0.5)
    lock.release()

eat_lst = ['alex','wusir','太白','yuan']
for name in eat_lst:  # 8个子线程 7个线程 3个线程eat1,4个线程eat2
    Thread(target=eat1,args=(name,)).start()
    Thread(target=eat2,args=(name,)).start()
View 解决方案第一版Code

解决方案第二版

import time
from threading import Thread,RLock
lock = RLock()
def eat1(name):
    lock.acquire()
    print('%s拿到了面' % name)
    lock.acquire()
    print('%s拿到了叉子' % name)
    print('%s在吃面'%name)
    time.sleep(0.5)
    lock.release()  # 0.01
    lock.release() # 0.01

def eat2(name):
    lock.acquire()  # 0.01
    print('%s拿到了叉子' % name) # 0.01
    lock.acquire()
    print('%s拿到了面' % name)
    print('%s在吃面'%name)
    time.sleep(0.5)
    lock.release()
    lock.release()

eat_lst = ['alex','wusir','太白','yuan']
for name in eat_lst:  # 8个子线程 7个线程 3个线程eat1,4个线程eat2
    Thread(target=eat1,args=(name,)).start()
    Thread(target=eat2,args=(name,)).start()
View Code


死锁:    多把锁同时应用在多个线程中
互斥锁和递归锁哪个好
    递归锁 快速恢复服务
    死锁问题的出现 是程序的设计或者逻辑的问题
    还应该进一步的排除和重构逻辑来保证使用互斥锁也不会发生死锁
互斥锁和递归锁的区别
     互斥锁 就是在一个线程中不能连续多次ACQUIRE
     递归锁 可以在同一个线程中acquire任意次,注意acquire多少次就需要release多少次

====================信号量=锁+计数器===============================

 

import time
from  multiprocessing  import Semaphore,Process,Pool
def ktv1(sem,i):
    pass

def ktv2(i):
    i+=1
if __name__ == '__main__':
    sem=Semaphore(5)
    start=time.time()
    p1=[]
    for i in range(100):
        p=Process(target=ktv1,args=(sem,i))
        p.start()
        p1.append(p)
    for p  in p1:
        p.join()
    print("###",time.time()-start)

    start = time.time()
    p = Pool(5)
    p_l = []
    for i in range(100):
        ret = p.apply_async(func=ktv2, args=(sem, i))
        p_l.append(ret)
    p.close()
    p.join()
    print('***',time.time() - start)
View Code

池 效率高
    池子里有几个一共就起几个
    不管多少任务 池子的个数是固定的
     开启进程和关闭进程这些事都是需要固定的开销
     就不产生额外的时间开销
     且进程程池中的进程数控制的好,那么操作系统的压力也小
信号量
     有多少个任务就起多少进程/线程
     可以帮助你减少操作系统切换的负担
     但是并不能帮助你减少进/线程开启和关闭的时间

==============事件===============================

# wait
    # 等 到 事件内部的信号变成True就不阻塞了
# set
    # 设置信号变成True
# clear
    # 设置信号变成False
# is_set
    # 查看信号是否为True

实例代码  数据库连接

import time
# import random
# from threading import Event,Thread
# def check(e):
#     '''检测一下数据库的网络和我的网络是否通'''
#     print('正在检测两台机器之间的网络情况 ...')
#     time.sleep(random.randint(0,2))
#     e.set()
#
# def connet_db(e):
#     n = 0
#     while n < 3:
#         if e.is_set():
#             break
#         else:
#             e.wait(0.5)
#             n += 1
#     if n == 3:
#         raise TimeoutError
#     print('连接数据库 ... ')
#     print('连接数据库成功~~~')
#
# e = Event()
# Thread(target=connet_db,args=(e,)).start()
# Thread(target=check,args=(e,)).start()
View Code

===================条件======================

from threading import Condition
# acquire
# release
# wait    阻塞
# notify  让wait解除阻塞的工具
# wait还是notify在执行这两个方法的前后 必须执行acquire和release
# from threading import Condition,Thread
# def func(con,i):
#     con.acquire()
#     # 判断某条件
#     con.wait()
#     print('threading : ',i)
#     con.release()
#
# con = Condition()
# for i in range(20):
#     Thread(target=func,args=(con,i)).start()
# con.acquire()
# # 帮助wait的子线程处理某个数据直到满足条件
# con.notify_all()
# con.release()
# while True:
#     num = int(input('num >>>'))
#     con.acquire()
#     con.notify(num)
#     con.release()
View Code

================定时器============

from threading import Timer
def func():
    print('执行我啦')

# interval 时间间隔
Timer(0.2,func).start()  # 定时器
# 创建线程的时候,就规定它多久之后去执行
View Code

 

posted @ 2018-07-30 16:10  山东张铭恩  阅读(105)  评论(0编辑  收藏  举报