并发 并行的区别?
并发:
在一个时间段内,多任务同时运行
并行:
在一个时间点上,多任务同时运行, 多核CPU
高并发问题
一、多进程
把每个任务,都分配给一个进程,由操作系统内核,对进程进行调度
优点:
由于进程是资源独立的,每个任务的资源不会出现抢占资源的问题,代码维护非常方便
缺点:
进程的资源消耗要比较大 资源切换时间
进程的切换也需要消耗系统时间 调度时间
二、多线程
优点:
资源的切换不需要时间,共享进程的
缺点:
切换也需要消耗系统时间
资源共享,互斥问题,代码书写上考虑临界资源的问题
引入锁
- 读锁
- 写锁
系统消耗时间分为
- CPU密集型
- 运算多
- IO密集型
- 借助硬件进行数据的读写操作
在python中线程:
线程 GIL 全局解释器锁
不适合CPU密集型
适合IO密集型,多线程爬虫
redis持久化:
- RDB
把内存中的数据,以镜像形式保存在硬盘上
配置:
save N M 在N秒内,有M次操作时,触发RDB的持久化
特点:
容易丢失数据
方案:
linux一个fork技术,产生一个新的子进程,进行持久化 ,写时拷贝技术 - AOF
把所有写redis的命令,以日志形式追加到持久化文件中
redis的数据一致性问题:
解决方案:
1. redis k-v对都有过期时间
2. 当后台管理页面,api接口 一旦有写入操作,就删除数据库的内容重新写入
阻塞IO模型:
- 阻塞IO模型
当发起一个请求(读、写)给了硬件,如果条件不满足,把当前线程切换为等待态一旦条件满足,才被唤醒
此时线程的后续代码,不会被执行,只有等待前序代码执行完成才能执行。
非阻塞模型
- 非阻塞IO模型
当发起一个请求(读、写)给了硬件,如果条件不满足,立刻从内核中返回,回到用户空间处client.setblocking(False),由于条件不满足,并没有等待条件的过程,而CPU运行时间非常的快,导致慢速IO还没有数据到来,程序就已经被CPU运行到数据处理部分
采用轮询方式,来知道慢速IO是否有数据到来
- 多路IO进行统一的事件监听管理 (异步模型)
异步编程的特性:
- 事件注册机制
向整个异步模型中提供的事件表中注册事件发生后的处理方案 - 死循环等待事件的发生(loopevent)
事件循环+回调机制的一种编程方式
把所有可能阻塞的IO处理部分,都分离成一个个回调函数
把这些回调函数注册到对应的事件上主循环中,利用操作系统提供的监听机制,等待事件触发
一旦有事件到来,操作系统会返回对应事件的对象从这个对象中,取出处理函数名,进行执行
redis 签到
保存在哪里,以什么格式进行维护,连续签到,如果中断签到,重新开始
在redis中,使用hash结构进行每个用户的签到数据维护
key的取值:
sign_用户ID号
value的取值:
哈希结构
date: 最近签到日期字符串
state: 签到次数
首次签到
hget获取不到值,说明首次
hset
正常的次日签到
当前天数 - date天数 <= 1
断签后的签到
当前天数 - date天数 > 1
bitmap签到技术的思路
- 设计思路
对于用户签到数据,如果每条数据都用K/V的方式存储,当用户量大的时候内存开销是非常大的。
而位图(BitMap)是由一组bit位组成的,每个bit位对应0和1两个状态,虽然内部还是采用String类型存储,但Redis提供了一些指令用于直接操作位图,可以把它看作是一个bit数组,数组的下标就是偏移量。
它的优点是内存开销小、效率高且操作简单,很适合用于签到场景。
Redis提供了以下几个指令用于操作位图:
- SETBIT
- GETBIT
- BITCOUNT
- BITPOS
- BITOP
- BITFIELD
特点:
- 节约空间
- 大量数据排序
外排序:指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。
归并排序:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 采用分而治之法