应用层、传输层、网络层、数据链路层、物理层
三层设备:路由器、三层交换机;四层协议:tcp协议/udp协议
三次握手
accept:服务器接收过程中等待客服端的连接
三次握手的过程再代码中是由accept和connect共同完成的,具体的细节在socket中没有体现出来
四次挥手
server端和client端对应的代码中都有close方法
可以结束两端的数据发送,表示连接断开了
tcp协议:面向连接的,流式的,可靠地,效率低的全双工通信
udp协议:面向数据报的,无连接的,不可靠,快的,能完成一对一,一对多,多对多的高效通讯协议。
tcp协议出现黏包是因为它无边界的流式传输特点导致的。
解析:
进程之间的内存是相互隔离的,因此数据也是相互隔离的。
实现:1.基于文件(队列,管道+锁)2.基于网络(第三方工具,socket)
特点:1.进程安全,2.数据量不宜过大,3.放取值阻塞
实现原理:基于管道+锁的原理,让不同进程对共享数据的修改有序化,从而保证了数据的安全。
生产者:负责制造数据的任务
消费者:负责将生产者产生的数据进行处理的任务
生产者消费模型:基于生产者产生数据,放入一个共享空间(队列),消费者从中取到数据进行处理的模型。
意义:1.实现了生产者和消费者的解耦合,2.平狠了生产力和消费力,生产者不停生产数据,消费者不停处理数据,二者通过队列进行沟通。
进程在计算机中类似工厂生产零件的车间,为生产过程开辟空间储备生产所需要的材料,在计算机中对应的就是开辟内存,存储运行代码和数据。
inter process communication,进程之间通信,基于管道、队列的第三方工具实现(redis,memcache,rabbitmq)
global interpreter lock全局解释其所,Cpython中,对解释器加的一把锁,导致同一时刻同一进程中只有一个线程能够访问cpu,GIL锁的出现,保证了多线程对共享数据的大部分操作,也就是类原子操作时的数据安全。但是无法避免所有修改共享数据的安全。
不是,在Cpython解释器中,代码都会转换成机器码,即时有了GIL锁的限制,多线程对数据的非原子性修改操作,也会因为操作系统的对cpu时间片轮转而导致对数据修改的不安全。
多道操作系统中,是指多个进程或线程在执行过程中,因争夺资源而造成的一种互相等待的僵局现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程/线程。
是,因为logging模块的写入是追加写
创建全局ThreadLocal对象:
localVal = threading.local()
localVal.val = "Main-Thread" # 为全局线程对象赋值
用来保存一个全局变量,只能在当前前线程中才能访问
不同线程对其赋值,不会覆盖,而会在自己的线程单独创建控件来存储这个变量
不同线程的前程变量local.val是隔离的,其他线程无法访问
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait,daemon = False)
t.start()
# flag b
0秒,因为线程的开启速度非常快,而且t.start()是异步非阻塞方法的,不会等待线程中的任务结束。
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait,daemon = True)
t.start()
# flag b
0秒,守护线程结束时间是在所有非守护线程结束后,而该进程中没有其他线程,所以主线程在异步执行start后立马结束,守护线程也被强制结束了。
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait,daemon = True)
t.start()
t.join()
# flag b
10秒,join方法会阻塞,同步等待线程任务执行完成才继续执行下一步
View Code
不一定,多线程对共享数据进行非原子操作,如+=,-=,*=,/=都有可能出现数据不安全。需要加互斥锁保证数据安全。
View Code
一定为0,因为在启动ta和ts后分别对ta,ts进行join,是将ta和ts异步执行变成了同步执行,ts会等待ta执行完毕后才执行,也就是同一时刻,只有一个代码去修改数值,这种修改是安全的。
View Code
一定为1,因为append是不可拆分操作,线程对数据的不可拆分操作不会导致数据不安全,而在每次取值都会等待,也不会出现取到空值报错的现象。所以一定为1。
View Code
一定为1,线程ta和ts是同步执行的,ta执行完后,ts才开始执行,线程同步执行修改数据,数据是安全的。
协程是一种用户级的轻量型线程,协程是由用户程序自己控制调度,是单线程下的并发,又称微线程,纤程,coroutine
常用模块:
greenlet:提供了切换任务的快捷方式,但是遇到io无法自动切换任务,需要手动切换
gevent:开启协程任务并切换的模块,遇到io自动切换任务。
阻塞等待调用join方法的协程任务执行完毕,然后继续往后执行。
join产生阻塞,gevent识别到阻塞后,自动切换任务,只要该协程任务没有完成,join会一直产生阻塞,从而使gevent不停的切换到该协程任务上执行。
协程实现并发server
协程访问url
进程:操作系统资源分配的最小单位,进程之间资源和地址空间独立,进程的创建、销毁、切换开销大,可以利用多核。高密集型计算。
线程:进程中的一条执行过程,操作系统执行的最小单位,共享当前进程的资源,创建、销毁、切换开销比进程小。单存计算模型
协程:基于用户级别控制的,线程中可以自由切换任务,无需操作系统调度,创建比线程更高效。爬虫数据处理。
开启一定数量的进程/线程不停轮流处理大量的任务,避免了不停开启/销毁线程/进程过程中的开销,从而提高处理任务的效率。
特点:只要有任务未处理完,进程池/线程池会自动开启进程/线程处理任务,知道池中进程/线程数量达到限制。每个进程/线程处理完任务,无需销毁,而是从新指令其他未完成的任务。
1.线程的开启、切换、销毁需要通过操作系统执行,协程的创建、切换、销毁是基于程序员自己控制。
2.协程的切换效率远高于线程的切换
3.协程本质上就是一个线程,所以也无法利用多核。
4.协程是数据安全的,但是线程数据不安全
不同点:互斥锁不能连续acquire,连续acquire会产生死锁现象;递归锁可以连续的acquire。
相同点:互斥锁和递归锁都可以保证同一段代码在同一时间只有一个线程执行。
队列,队列内部自动实现了锁的机制,同一时间只有能一个对象对队列中的元素修改
使用concurrent.futures模块中的ProcessPoolExecutor类和ThreadPoolExecutor类,创建进程池和线程池。
p = ProcessPoolExecutor(maxsize)获得进程池对象
t = ThreadPoolExecutor(maxsize)获得线程池对象
使用submit向池中添加任务,获得一个任务对象
对任务对象使用result获取任务的返回值
并行:多个程序在同一时刻使用多个cpu处理任务,是真正的同时运行
并发:多个程序交替在一个cpu上处理任务,看起来像同时运行
同步:发起一个任务,原地等待该任务执行结束返回结果,才继续执行后续代码。
异步:发起一个任务,不等待该任务执行结束,就直接执行后续代码。
异步非阻塞,执行效率最高的模式,发起任务,不等待结果,直接执行自己的任务,任务在执行过程中没有阻塞操作,充分提高了CPU的计算效率。
sem = semaphore(5) 获得一个信号量对象
同一可以允许一定数量的进程/线程执行某一段代码,之后的进程/线程需要等待其中任务释放掉信号量锁,才能获取锁,执行该段代码。
一切io操作即向内存中写入和从内存中取出,如读取文件,写入文件,获取用户数据,
进程实现消费者生产者模型
线程实现生产者消费者模型
协程实现生产者消费者模型
原文:https://www.cnblogs.com/ryxiong-blog/p/12988763.html