高并发 基础 概念

单线程 : 一定等之前请求处理完毕,才可以处理下一个请求。
多线程 : 之前的请求如果阻塞,可以直接继续发送下一个请求,而不必等待之前的请求结束。

定律:一个CPU核心在同一个时间片里,只能执行一个程序任务。
    双核心CPU在同一个时间片里,可以执行两个程序任务(多任务)
    双核心四线程(超线程技术Intel):一个核心有两个逻辑处理器

并行 : 多个CPU核心同时执行多个任务(CPU数 >= 任务数)
任务1: -----------
任务2: -----------
任务3: -----------

并发 : 单个CPU核心可以串行执行多个任务(CPU数 < 任务数)
任务1:------ ------
任务2: ------
任务3: ------

进程和线程:本质都是操作系统执行任务的调度单位。

进程: 上下文管理器(打开、执行读写、关闭),每个程序在运行时,都需要一个进程。
1. 每个进程都有自己独立的内存空间;
2. 不同进程之间的内存空间不能共享(通信效率低、切换开销大)
3. 可以充分利用计算机的多核CPU性能。

什么时候用多进程:CPU密集任务(大量的并行计算),且不需要切换任务

线程:每个程序运行时需要一个进程;程序的多个功能可以通过线程控制(执行功能a、执行功能b)
1. 同一个进程下,可以存在多个线程,线程可以共享进程的内存空间
2. 同一个进程下的不同线程,通信效率高、切换开销小
3. 现代操作系统执行任务都是"抢占式",共享意味着竞争,就会导致数据访问的安全问题。
4. 多线程同时访问数据访问的安全问题,可以通过"互斥锁"解决。
5. 互斥锁:让多个线程 可以安全有序的访问 进程内存空间的机制。

什么时候用多线程:IO密集任务(网络IO、磁盘IO、数据库IO),切换开销小

不同编程语言,线程的执行方式会不一样:编译型语言(一次可以执行多个线程=并行)、解释型语言(一次只能执行一个线程-并发)
编译型语言: 程序执行前 确定数据类型(代码编写速度慢,需要类型检查,代码稳定)
解释型语言: 程序执行时 确定数据类型(代码编写速度块,不需要类型检查,粗心会导致代码不稳定)

*** Python为了防止多线程滥用导致代码问题,所以提供了 GIL 全局解释器锁:***
1. 线程执行任务,必须获取GIL才能执行
2. 一个Python解释器环境下,只有一个GIL,
3. 但是,当某个线程序有IO阻塞操作时,会自动释放GIL,尝试让其他线程工作。
4. 如果某个线程一直占用GIL,默认在100次操作后释放GIL (sys.getcheckinterval())

协程: 不是操作系统调度单位,单线程执行,没有CPU的切换开销。
本质一个生成器, 通过 yield 返回数据/继续执行。
当IO阻塞时,通过yield 挂起任务;当阻塞结束时,再继续执行任务。

什么时候用多协程:网络IO密集任务,没有切换开销

10个网页,每个网页需要1秒后才能打开。

多进程: from multiprocessing import Pool
多线程: threading、 from multiprocessing.dummy import Pool
协程: genvet、
猴子补丁: gevent.monkey.patch_all() 将Python底层的网络库打个补丁,在执行网络IO任务时按异步的方式执行。

同步、异步 : 执行方式
阻塞、非阻塞 : 执行状态

同步阻塞 : 同步的代码执行方式,程序会有阻塞状态。
异步非阻塞 : 异步的代码执行方式,程序就是非阻塞状态。

队列:Python提供的一种线程安全的容器(不必处理锁,即可实现多线程的IO访问)

from queue import Queue

q = Queue(10)

q.put(10):如果队列未满,可以继续放数据;如果队列为满,则阻塞
q.get() : 如果队列有值,则取出数据;如果队列数据没有值,则阻塞。

q.put_nowait(10) : 如果队列未满,可以继续放数据;如果队列为满,抛出 Full 异常。
q.get_nowait()如果队列有值,则取出数据;如果队列数据没值,抛出 Empty 异常。

q.qsize() : 查看队列里数据个数
q.empty() : 判断队列是否为空,如果为空则返回True;不为空返回False

q.put() : 当q.put() 存入数据时,队列的计数器会自增1
q.get() : 当q.get() 取出数据时,队列的计数器 不会 减1
q.task_done() ; 当q.get() 后,再执行异常 q.task_done() 则计数器会减1

q.join() : 当q 队列的计数器 不为 0 时,则主线程阻塞,等待子线程工作;当 队列的计数器为 0 时,主线程才会继续向下执行代码。

主线程 结束,代表程序结束。
子线程

主进程和主线程结束,默认子进程和子线程不会结束,只有守护进程和守护线程才会结束。

from multiprocessing.dummy import Pool
from genvet.pool import Pool

pool = Pool()

#线程池和协程池 四种方法的参数和执行机制一样

  1. result_list = pool.map(func, args_list) :
    将 args_list 里的每个元素依次做为参数传递给 func 执行,并将所有的返回值全部保存在 resutl_list

  2. pool.map_async(func, args_list, callback)
    将 args_list 里的每个元素依次做为参数传递给 func 执行,并将所有的返回值全部保存在列表,并传递给 callback指定的函数执行

  3. result = pool.apply(func, args)
    将 args 做为参数传递给 func 执行,并将返回值保存在result中

  4. pool.apply_async(func, args, callback)
    将 args 做为参数传递给func执行,并将返回值传递个 callback 指定的回调函数

注意:协程池没有close

pool.close()
pool.join()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值