GIL
python使用多线程, 一定运行速度快么? 为什么?
- GIL(global interpreter lock)
- python解释器中任意时刻都只有一个线程在执行;
- GIL执行过程:
- 1). 设置一个GIL;
- 2). 切换线程去准备执行任务(Runnale就绪状态);
- 3). 运行;
- 4). 可能出现的状态:
- 线程任务执行结束;
- time.sleep()
- 需要获取其他的信息才能继续执行(eg: 读取文件, 需要从网络下载html网页) - 5). 将线程设置为睡眠状态;
- 5). 解GIL的锁;
多线程的应用场景: I/O密集型(input, output) — 爬虫
不建议使用多线程的场景: 计算密集型(cpu一直占用)
import threading
from day20.mytimeit import timeit
def job(li):
return sum(li)
@timeit
def use_thread():
li = range(1, 10001)
# create 5 threads
threads = []
for i in range(5):
t = threading.Thread(target=job, args=(li, ))
t.start()
threads.append(t)
[thread.join() for thread in threads]
@timeit
def use_no_thread():
li = range(1, 10001)
for i in range(5):
job(li)
if __name__ == "__main__":
use_thread()
use_no_thread()
队列与线程
1). 理论上多线程执行任务是不能获取返回结果的, 因此需要一个容器来存储产生的数据;
2). 容器该如何选择? list(栈, 队列), tuple(元组是不可变的, 不可使用),
set(集合默认会去重, 所以不选择), dict
选择队列类型存储(FIFO===first input first output)
import threading
from day20.mytimeit import timeit
from queue import Queue
def job(li, queue):
queue.put(sum(li)) # 将任务的执行结果存储到队列中;
@timeit
def use_thread():
# 实例化一个队列, 用来存储每个线程执行的结果
q = Queue()
# q.get() -- 出队
# q.put(value) -- 入队
lis = [range(5), range(2,10), range(1000, 20000), range(3000, 10000)]
# create 5 threads
threads = []
for li in lis:
t = threading.Thread(target=job, args=(li, q))
t.start()
threads.append(t)
[thread.join() for thread in threads]
# 从队列中拿出所有线程执行的结果;
results = [q.get() for li in lis]
print(results)
if __name__ == "__main__":
use_thread()
生产者消费者模型、类的继承实现
需求1: 给定200个ip地址, 可能开放端口为80, 443, 7001, 7002, 8000, 8080,
9000(flask), 9001
以http://ip:port形式访问页面以判断是否正常访问.
1). 构建所有的url地址;===存储到一个数据结构中
2). 依次判断url址是否可以成功访问
实现多线程:
1). 实例化对象threading.Thread;
2). 自定义类, 继承threading.Thread, 重写run方法(存储任务程序);
什么是生产者-消费者模型?
某个模块专门负责身缠数据, 可以认为是工厂;
另外一个模块负责对生产的数据进行处理的, 可以认为是消费者.
在生产者和消费者之间加个缓冲区(队列queue实现), 可以认为是商店.
生产者 -----》缓冲区 -----》 消费者
优点:
1). 解耦:生产者和消费者的依赖关系减少;
2). 支持并发;是两个独立的个体, 可并发执行;
def create_data():
"""创建测试数据, 文件中生成200个IP"""
with open('doc/ips.txt', 'w') as f:
for i in range(200):
f.write('172.25.254.%s\n' % (i + 1))
print("测试数据创建完成!")
import time
import threading
from queue import Queue
from urllib.request import urlopen
class Producer(threading.Thread):
def __init__(self, queue):
super(Producer, self).__init__()
self.q = queue
def run(self):
"""生产测试需要的url地址http://ip:port"""
ports = [80, 443, 7001, 7002, 8000, 8080, 9000, 9001]
with open('doc/ips.txt') as f:
for line in f:
ip = line.strip()
for port in ports:
url = "http://%s:%s" %(ip, port)
time.sleep(1)
self.q.put(url)
print("生产者生产url:%s" %(