037-2018-1029 线程池 事件 队列 线程其他方法 协程 greenlet gevent

笔记

 

昨日内容回顾:

线程 两种创建方式

线程与进程效率对比

同一进程下线程的共享进程的资源的

锁(同步锁\互斥锁 Lcok) :

死锁现象:当我们使用锁嵌套锁的时候,多个线程异步执行的时候会出现线程之前互相等待对方未释放的锁.

递归锁RLock :

守护线程:所有非守护线程结束才结束,主线程的代码结束,只要还有非守护线程,那么守护线程也不会结束

守护进程:主进程代码结束,守护进程结束

信号量: 大宝剑!!!

今日内容:

线程的一些其他方法  #

线程事件  #

线程队列 重点 #import queue

先进先出

Queue.Queue()

后进先出

优先级队列

线程池 重点,from concurrent.futures import ThreadPoolExecutor,

GIL锁 重点

 

协程的认识

Greenlet

Gevent #重点

明日预习内容

https://www.cnblogs.com/clschao/articles/9712056.html

明日默写:

GIL锁

线程池中的几种方法,每个方法干什么用的写一下

作业:

1 通过线程池写一个并发的爬虫的程序,需要应用回调函数

2 自行完成一个简单的socketserver,使用面向对象+多线程来实现

gevent使用

GIL锁

#解释:
import time
time.sleep(50)


greenlet使用


  #真正的协程模块就是使用greenlet完成的切换
# import time
# from greenlet import greenlet
#
# def eat(name):
#     print('%s eat 1' %name)  #2
#     time.sleep(3)
#     g2.switch('taibai')   #3
#     print('%s eat 2' %name) #6
#     g2.switch() #7
# def play(name):
#     print('%s play 1' %name) #4
#     time.sleep(3)
#     g1.switch()      #5
#     print('%s play 2' %name) #8
#
# g1=greenlet(eat)
# g2=greenlet(play)
#
# g1.switch('taibai')#可以在第一次switch时传入参数,以后都不需要














事件

from threading import Thread,Event

e = Event()  #e的状态有两种,False True,当事件对象的状态为False的时候,wait的地方会阻塞

e.set()  #将事件对象的状态改为True
e.clear() #将事件对象的状态改为Flase
print('在这里等待')
e.wait() #阻塞
print('还没好!!')




协程

#协程:单线程下实现并发
#并发:伪并行,遇到IO就切换,单核下多个任务之间切换执行,给你的效果就是貌似你的几个程序在同时执行.提高效率
#任务切换 + 保存状态
#并行:多核cpu,真正的同时执行
#串行:一个任务执行完在执行另外一个任务

#多线程多进程下的任务切换+保存状态是操作系统
#

# 串行
# import time
#
# def func1():
#     time.sleep(1)
#     print('func1')
#
# def func2():
#     time.sleep(2)
#     print('func2')
#
# if __name__ == '__main__':
#     func1()
#     func2()

#基于yield并发执行,多任务之间来回切换,这就是个简单的协程的体现,但是他能够节省I/O时间吗?不能
import time
def consumer():
    '''任务1:接收数据,处理数据'''
    while True:
        x=yield
        # time.sleep(1) #发现什么?只是进行了切换,但是并没有节省I/O时间
        print('处理了数据:',x)
def producer():
    '''任务2:生产数据'''
    g=consumer()
    # print('asdfasfasdf')
    next(g)  #找到了consumer函数的yield位置
    for i in range(3):
    # for i in range(10000000):
        g.send(i)  #给yield传值,然后再循环给下一个yield传值,并且多了切换的程序,比直接串行执行还多了一些步骤,导致执行效率反而更低了。
        print('发送了数据:',i)
start=time.time()
#基于yield保存状态,实现两个任务直接来回切换,即并发的效果
#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.
producer() #我在当前线程中只执行了这个函数,但是通过这个函数里面的send切换了另外一个任务
stop=time.time()

# 串行执行的方式
res=producer()
consumer(res)
stop=time.time()

print(stop-start)

回调函数


import time

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import current_thread

def func(n):
    time.sleep(1)
    # print(n,current_thread().ident)
    print(n,current_thread().getName())

    return n**2

def func2(n):
    # print('>>>>>>>',n)
    # print('>>>>>>>',n.result())
    print('current_thread>>>>',current_thread().getName())

if __name__ == '__main__':
    t_p = ThreadPoolExecutor(max_workers = 4)
    # t_p = ProcessPoolExecutor(max_workers = 4)
    for i in range(3):
        t_p.submit(func,i).add_done_callback(func2)

    print('主线程结束')

多线程和多进程进行纯计算效率

import time
from multiprocessing import Process
from threading import Thread

# def func():
#     num = 0
#     for i in range(1,100000000):
#         num += i

def func():
    time.sleep(2)
    print('xxxxxxxx')

if __name__ == '__main__':
    p_s_t = time.time()
    p_list = []
    for i in range(10):
        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

    t_s_t = time.time()
    t_list = []
    for i in range(10):
        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

    print('多进程执行的时间',p_dif_t)
    print('多线程执行的时间',t_dif_t)




线程池

import time

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import current_thread

def func(n):
    time.sleep(1)
    # print(n,current_thread().ident)
    return n**2

if __name__ == '__main__':
    t_p = ThreadPoolExecutor(max_workers = 4)
    map_res = t_p.map(func,range(10)) #异步执行的,map自带join功能
    print(map_res)
    print([i for i in map_res])

线程池的一些其他方法

import time

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import current_thread

def func(n):
    time.sleep(1)
    # print(n,current_thread().ident)
    return n**2

def func2(n):
    print(n)


if __name__ == '__main__':
    t_p = ThreadPoolExecutor(max_workers = 4)
    # t_p = ProcessPoolExecutor(max_workers = 4)
    # t_p.submit(func,n = 1)
    t_res_list = []
    for i in range(10):
        # res_obj = t_p.submit(func,i) #异步提交了这个10个任务,
        res_obj = t_p.submit(func,i) #异步提交了这个10个任务,
        # res_obj.result() #他和get一样
        t_res_list.append(res_obj)

    t_p.shutdown()  #close + join

    print('t_res_list',t_res_list)

    for e_res in t_res_list:
        print(e_res.result())


线程的一些其他方法


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

def work():
    import time
    time.sleep(1)
    # print('子线程',threading.get_ident()) #2608
    print(threading.current_thread().getName()) #Thread-1
    print(threading.current_thread()) #Thread-1

if __name__ == '__main__':
    #在主进程下开启线程
    t=Thread(target=work)
    t.start()

    # print(threading.current_thread())#主线程对象 #<_MainThread(MainThread, started 1376)>
    # print(threading.current_thread().getName()) #主线程名称 #MainThread
    # print(threading.current_thread().ident) #主线程ID #1376
    # print(threading.get_ident()) #主线程ID #1376

    time.sleep(3)
    print(threading.enumerate())  # 连同主线程在内有两个运行的线程,[<_MainThread(MainThread, started 13396)>, <Thread(Thread-1, started 572)>]
    print(threading.active_count()) # 2
    print('主线程/主进程')


通过生成器来实现的单线程下的并发

import time
# def consumer():
#     for i in range(10):
#         # x=yield
#         time.sleep(1)
#         print('处理了数据:',i)
# def producer():
#     g=consumer()
#     next(g)
#     for i in range(3):
#         g.send(i)
#         print('发送了数据:',i)
# #
# start=time.time()
# producer()
# stop=time.time()
# print(stop-start)


# import time
# def consumer():
#     for i in range(4):
#         time.sleep(1)
#
#         print('处理了数据:',i)
# def producer():
#     for i in range(3):
#         print('发送了数据:',i)
#
# start=time.time()
# consumer() #3.00097393989563
# producer()
# stop=time.time()
# print('>>>>>',stop-start)

import time
def consumer():
    for i in range(4):
        x = yield
        time.sleep(1)
        print('处理了数据:',i)
def producer():
    g = consumer()
    next(g)
    for i in range(3):
        g.send(i)
        print('发送了数据:',i)

# greenlet


# start=time.time()
# producer()
# stop=time.time()
# print(stop-start)





队列


import queue
#先进先出 FIFO

# q=queue.Queue()
# q.put('first')
# q.put('second')
# q.put('third')
# # q.put_nowait() #没有数据就报错,可以通过try来搞
# print(q.get())
# print(q.get())
# print(q.get())
# # q.get_nowait() #没有数据就报错,可以通过try来搞
# '''
# first
# second
# third
# '''


#后进先出,先进后出
# import queue
#
# q=queue.LifoQueue() #队列,类似于栈,栈我们提过吗,是不是先进后出的顺序啊
# q.put('first')
# q.put('second')
# q.put('third')
# # q.put_nowait()
#
# print(q.get())
# print(q.get())
# print(q.get())
# # q.get_nowait()
#
# '''
# third
# second
# first
# '''

#优先级队列

import queue

q=queue.PriorityQueue()
#put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
q.put((-10,'a'))
q.put((-5,'a'))  #负数也可以
# q.put((20,'ws'))  #如果两个值的优先级一样,那么按照后面的值的acsii码顺序来排序,如果字符串第一个数元素相同,比较第二个元素的acsii码顺序
# q.put((20,'wd'))
# q.put((20,{'a':11})) #TypeError: unorderable types: dict() < dict() 不能是字典
# q.put((20,('w',1)))  #优先级相同的两个数据,他们后面的值必须是相同的数据类型才能比较,可以是元祖,也是通过元素的ascii码顺序来排序

# q.put((20,'b'))
# q.put((20,'c'))
q.put((20,'a'))
q.put((0,'b'))
q.put((30,'c'))

print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
# print(q.get())
# print(q.get())
'''
结果(数字越小优先级越高,优先级高的优先出队):
'''

猜你喜欢

转载自blog.csdn.net/David_lyy/article/details/86441575