33 python Threading模块与线程 线程池 GIL锁

---恢复内容开始---

一 python Threading模块与线程

  multiprocess模块完全模仿了threading模块的接口,二者在使用层面有较大的相似处。

1. 线程的创建

from threading import Thread
def func(m):
    print(m)

if __name__ == '__main__':
    f = Thread(target=func,args=(1,)) #创建一个线程对象
    f.start()
    print('主进程结束')
方式一
from threading import Thread
class Mythread(Thread):
    def __init__(self,m):
        super().__init__()#继承Thread模块的init
        self.m = m
    def run(self):
        print('拉拉爱了')

    def norun(self): #还可以写其他的方法
        print('啦啊的')

if __name__ == '__main__':
    m = Mythread('e') #传递自己的变量
    m.start()
    m.norun()
方式二

2.多线程和多进程运行的效率对比

ort time
from threading import Thread
from multiprocessing import Process

def func():
    pass

if __name__ == '__main__':

    t_list = []
    t_s_t = time.time()
    for i in range(100):
        t = Thread(target=func,)
        t_list.append(t)
        t.start()
    [tt.join() for tt in t_list]#等待子程序
    t_e_t = time.time()
    t_dif_t = t_e_t - t_s_t

    p_list = []
    p_s_t = time.time()
    for i in range(100):
        p = Process(target=func,)
        p_list.append(p)
        p.start()
    [pp.join() for pp in p_list]#等待子程序
    p_e_t = time.time()
    p_dif_t = p_e_t - p_s_t
    print('多线程的时间>>>',t_dif_t)#0.025949478149414062
    print('多进程的时间>>>',p_dif_t)#7.810645341873169

    print('主线程结束')
效率对比

3 多线程数据共享

import time
from threading import Thread

num = 100
def func():
    # time.sleep(3)
    global num
    tep = num
    time.sleep(0.001)
    tep = tep - 1
    num = tep
    # num -= 1

if __name__ == '__main__':
    t_list = []
    for i in range(100):
        t = Thread(target=func,)
        t_list.append(t)
        t.start()
    [tt.join() for tt in t_list]
 
    print('主线程的num',num) #87 由于共享时会争抢数据并没有变为0
验证
import time
from threading import Thread,Lock

num = 100
def func(tl):
    time.sleep(1)
    global num
    tl.acquire()
    tep = num
    time.sleep(0.001)
    tep = tep - 1
    num = tep
    tl.release()

if __name__ == '__main__':
    tl = Lock()
    t_list = []
    for i in range(10):
        t = Thread(target=func,args=(tl,))
        t_list.append(t)
        t.start()
    [tt.join() for tt in t_list]
    # t.join()
    print('主线程的num',num)
枷锁解决数据共享不安全

4 守护线程守护进程

import time
from threading import Thread
from multiprocessing import Process

def func1():
    time.sleep(3)
    print('任务1结束')

def func2():
    time.sleep(2)
    print('任务2结束')

if __name__ == '__main__':
    p1 = Process(target=func1,)
    p2 = Process(target=func2,)
    #守护进程:主进程代码结束,守护进程结束,由于程序具有回收机制,所以要等待非守护子进程执行完,才结束。
    p1.daemon = True
    # p2.daemon = True
    p1.start()
    p2.start()
    t1 = Thread(target=func1,)
    t2 = Thread(target=func2,)
    t1.daemon = True
    t2.setDaemon(True)  #将t2设置为守护线程
    #守护线程:主程序等所有非守护线程结束才结束
    t1.setDaemon(True)  #将t1设置为守护线程
    t1.start()
    t2.start()
    print('主进程结束')
守护线程

5 信号量

import time
import random
from threading import Thread,Semaphore

def func1(i,s):
    s.acquire()
    # time.sleep(1)
    print('客官%s里边请~~'%i)
    time.sleep(random.randint(1, 3))
    s.release()


if __name__ == '__main__':
    s = Semaphore(4)
    for i in range(10):
        t = Thread(target=func1,args=(i,s))
        t.start()
信号量

6 事件

事件的
from threading import Thread,Event

e = Event()  #默认是False,

# print(e.isSet())
print('开始等啦')

e.set() #将事件对象的状态改为True
print(e.isSet())
# e.clear() #将e的状态改为False

e.wait()  #如果e的状态为False,就在这里阻塞
print('大哥,还没完事儿,你行')

7 线程队列

import queue      #先进先出队列
q = queue.Queue(3)
q.put('first')
q.put('second')
q.put(3)
# q.put(6)  #队列长度为3 当放过超过这个长度时程序就会一直等待前面的元素被拿
# 此时就可以用put_nowait()配合try来使用
try:
    q.put_nowait(3)
except:
    print('队列满了')
# print(q.qsize())#队列长度

print(q.get())
print(q.get())
print(q.get())
try:
    print(q.get_nowait())
except:
    print('队列没有了')


import queue      #先进后出队列
q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)
print(q.get()) #3
print(q.get())#2
print(q.get())#1

import queue
q = queue.PriorityQueue()#自定义排序
q.put((0,10))
q.put((-1,4))
q.put((6,9))
print(q.get())#(-1, 4)
print(q.get())#(0, 10)
print(q.get())#(6, 9)
几种队列

8 线程池

import time
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
#上面导入的是线程池和进程池(另外一种导入法)
from multiprocessing import Pool
def func(n):
    time.sleep(1)
    # print(n*n)
    return n*n
if __name__ == '__main__':
    t = ThreadPoolExecutor(4)
    # p = ProcessPoolExecutor(4) #创建进程池,其他的方法完全一样
    res_lis = []
    for i in range(10):
        res = t.submit(func,i) #异步提交线程,拿到结果对象
        # print(res.result()) #等待结果阻塞,拿到就再执行下一个循环,串行
        res_lis.append(res)
    t.shutdown()  # 放在此处此时所有结果对象都有结果直接全部拿到
    for res in res_lis:
        print(res.result())
    # t.shutdown()  # 等待子线程结束,和进程里面close()+join()差不多,此时上面for结果会四个四个打印结果
    print('主进程结束')

# 进程池
# if __name__ == '__main__':
#     p = Pool(4)
#     for i in range(10):
#         res = p.apply_async(func,(i,))
#         print(res.get())
线程池和进程池创建方法

9 线程池的map方法

import time
from concurrent.futures import ThreadPoolExecutor

def func(n):
    # print(n)
    time.sleep(1)

    return n*n
if __name__ == '__main__':
    t = ThreadPoolExecutor(4)
    res = t.map(func,range(10))#只是提交任务主程序不会等待
    for m in res:        #生成器对象
        print(m)
    print('主进程结束')
线程池map返回值为一个生成器

10 线程池,进程池的返回函数

import time
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from multiprocessing import Pool
def func(n):
    return n*n

def call_back(i):

    print('>>>>',i)
    print(i)

if __name__ == '__main__':
    # p = Pool(4)
    t = ThreadPoolExecutor(4)
    p = ProcessPoolExecutor(4)
    lis = []
    for i in range(10):   #线程池的方法
        res = t.submit(func,i).add_done_callback(call_back)
        lis.append(res)   #返回的都是结果对象
    for i in lis:
        print(i.result())

    for i in range(10):  # 进程池的方法
        res = t.submit(func,i).add_done_callback(call_back)

    for i in range(10):
        res = p.apply_async(func,(i,),callback=call_back)
        print(res.get())

    # p.close()
    # p.join()
    print('sssss')
call_back

 二  GIL锁

Gil锁(Global Interpreter Lock)

python全局解释器锁,有了这个锁的存在,python解释器在同一时间内只能让一个进程中的一个线程去执行,这样python的多线程就无法利用多核优势,但是这并不是python语言本身的缺点,是解释器的缺点,这个问题只存在于Cpython解释其中,像Jpython就没有。但是Cpthon是python官方解释器(算目前运行效率最高的吧),所以多数人都以为Gil锁是python语言的弊端。

 

过程解释:

1、加载python解释器代码

2、加载自己的py文件

3、py文件作为参数传给解释器(因为有GIL锁,一次只能一个线程进入)

4、解释器将py文件编译成.pyc字节码文件

5、解释器通过虚拟机将字节码文件转为二进制文件

6、二进制文件等待cpu调用

---恢复内容结束---

猜你喜欢

转载自www.cnblogs.com/-0121/p/10060985.html
今日推荐