并发和并行的区别
-
并行,
parallel
- 同时做某些事,可以互不干扰的同一个时刻做几件事
-
并发,
concurrency
- 也是同时做某些事,但是强调一个时段内有事情要处理
举例:
-
乡村公路一条车道,半幅路面出现了坑,交警指挥交通
-
众多车辆在这一时段要通过路面的事件,这就是并发
-
高速公路的车道,双向4车道,所有车辆(数据)可以互不干扰的在自己的车道上奔跑(传输)
-
在同一时刻,每条车道上可能同时有车辆在跑,是同时发生的概念,这是并行。
并发的解决:
高并发的解决
-
-队列、缓冲区
- 队列是一种天然解决并发的办法,解决了资源使用的问题
- 拍成的队列其实就是一个缓冲地带,就是缓冲区
- 可以有优先队列
- 例如
queue
模块的类Queue
、LifoQueue
、PriorityQueue
。
-
争抢
-
只开一个窗口,可能没有秩序,也就是谁挤进去就给谁
-
挤到窗口的人占据窗口,直到完成离开
-
其他人继续争抢,会有一个占据窗口,可以视为锁定窗口,窗口就不能为其他人提供服务了,这是一种锁机制
-
争抢也是一种高并发解决方案,但是,这样不好,因为可能有人很长时间抢不到
-
-
预处理
-
一种提前加载用户需要的数据的思路,预处理思想,缓存常用
-
加载多少,区分热,冷数据
-
-
并行
-
一个队列搞不定,多开窗口形成多个队列,如同开多个车道一样,并行处理
-
多开窗口,造成成本上升
-
日常可以通过购买更多服务器,或多开进程、线程实现并行处理,来解决并发问题
-
这些都是水平扩展思想
-
如果线程在单CPU上处理,就不是并行了
-
但是大多数服务器都是多CPU的,服务的部署往往是多机的、分布式的,这都是并行处理。
-
2个CPU叫两路,每个CPU有多核,每一个核心认为是一个CPU
-
-
-
提速
-
提高单个窗口的处理速度,也是解决并发的方式
-
提高单个CPU性能,或单个服务器安装更多的CPU
-
这是一种垂直扩展思想
-
-
消息中间件
-
上地,西二旗地铁站外的九曲回廊的走廊,缓冲人流,进去之后在进行安检进站
-
常见的消息中间件有
RabbitMQ
、ActiveMQ(Apache)
、RocketMQ(阿里Apache)
、kafka(Apache)
等。 -
当然还有其他手段解决并发问题,但是已经列举除了最常用的解决方案,一般来说不同的并发场景用不同的策略,而策略肯能是多种。
-
方式的优化组合
-
技术来源于生活
-
进程和线程
-
在实现了线程的操作系统中,线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。它被包含在进程之中,是进程中的实际单位。一个程序的执行实例就是一个进程。
-
进程
(process)
是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的而基本单位,是操作系统结构的基础。
进程和程序的关系
- 程序是源代码编译后的文件,而这些文件存放在磁盘中。当程序被操作系统加载到内存中,就是进程,进程中存放着指令和数据(资源),它也是线程的容器
- Linux进程有父进程、子进程,Windows的进程是平等关系。
- 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单位。
- 一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
- 在许多系统中,创建一个线程比创建一个进程快10-100倍。
进程、线程的理解
- 现代操作系统提出进程的概念,每一个进程都认为自己独占所有的计算机硬件资源。
- 进程就是独立的王国,进程间不可以随便的共享数据
- 线程就是省份,同一个进程内的线程可以共享进程的资源,每一个线程拥有自己独立的堆栈
python中的进程和线程
- 进程会启动一个解释器进程,线程共享一个解释器进程
- 一个线程跑一个函数
python的线程开发
- 使用标准库
threading
- 通过
threading.Thread
创建一个线程对象,target
是目标函数,name
可以指定名称 - 需要调用
start
方法,启动线程
线程退出
- python没有提供线程退出的方法,线程在下面情况时退出:
- 线程函数内语句执行完毕
- 线程函数中抛出未处理的异常
python的线程没有优先级、没有线程组的概念,也不能被销毁、停止、挂起、那也就没有恢复、中断了。
start()
方法会调用run()
方法,而run()
方法运行函数- 使用
start()
启动线程,启动了一个新的线程,但是使用run()
,并没有启动新的线程,就是在主线程中调用了一个普通的函数而已 - 因此,启动线程需使用
start()
方法,才能启动多个线程
多线程
- 一个进程中如果有多个线程,就是多线程,实现一种并发
- 当使用
start()
启动线程后,进程内有多个活动的线程并行的工作,就是多线程。 - 一个进程中至少有一个线程,并作为程序的入口,这个线程就是主线程。一个进程至少有一个主线程。
线程安全
- 线程执行一段代码,不会产生不确定的结果,那这段代码就是线程安全的。
print()
函数在线程中会被打断,被线程切换打断了,这种情况发生的时机不确定。print()
函数分两步,第一步打印字符串,第二部换行,就在这之间,发生了线程的切换。print()
函数是线程不安全的- 如果是这样,多线程编程的时候,
print
输出日志,不能保证一个输出后面一定换行了,怎么办?- 不让
print
打印换行format
格式化输出,手动加换行'\n'
- 字符串是不可变的类型,它可以作为一个整体不可分割输出。
end=''
就不在让print
输出换行了。
- 使用
logging
- 标准库里的
logging
模块,日志处理模块,线程安全的,生成环境代码都使用logging
。
- 标准库里的
- 不让