深刻理解:线程,进程,协程和并行,并发-协程

爬虫的并发控制:python

多进程、多线程、协程 yield程序员


从硬件:redis

双核四线程(超线程技术):
有两个CPU核心,每一个核心有两个逻辑处理器,至关于有四个CPU核心数据库


四核四线程:
有一个CPU核心,每一个核心有一个逻辑处理器,至关于有四个CPU核心设计模式


从操做系统:缓存

进程和线程,都是CPU任务的执行单位。安全


进程:早期的操做系统是面向进程的:
表示一个程序的执行活动(打开、执行、保存、关闭)网络


线程:如今的操做系统都是面向线程:
表示一个进程处理任务时最小调度单位(执行功能a、执行功能b)多线程


一个程序至少开启一个进程,一个进程至少有一个线程。并发

 

每一个进程都有独立的内存空间,不一样进程之间不共享任何状态。
进程之间的通讯须要通过操做系统调度控制,通信效率低、切换开销大。


同一个进程里的多个线程,是共享内存空间,切换开销小,通信效率高。
线程的工做机制是"抢占式",出现竞争的状态,竞争意味着数据不安全。
引入了"互斥锁":让多个线程安全有序的访问内存空间的机制。

 

Python的多线程:
相似于 GIL(全局解释器锁):保证一个时间片里只有一个线程在运行。
好处:直接杜绝了多个线程的竞争问题:
坏处:Python的多线程不是真正的多线程。

Python解释器在处理IO阻塞类型的方法时,会释放GIL
若是没有IO操做,该线程会每隔 sys.getcheckinterval() 次释放GIL,让其余线程尝试执行。

 


并行:
同一CPU时间片内,CPU能够同时处理多个程序。若是有多个程序,同步执行。

程序1:----------------
程序2:----------------
程序3:----------------
程序4:----------------

 

并发:
同一CPU时间片,只能处理一个程序。若是有多个程序,交替执行。

程序1: ----- ------
程序2: -----
程序3: ----
程序4: -----


多进程:能够充分利用多核CPU的资源,适用于密集CPU任务(大量的并行运算)
Python的多进程模块:multiprocessing

进程之间通讯成本高切换开销大,不适用于须要大量数据通讯和切换的任务(爬虫)

设计模式:生产者消费者(并行模式)

 

多线程:适用于密集I/O任务(磁盘IO,内存IO,网络IO),切换开销小通讯成本低。
Python的多线程:Thread、thraeding、multiprocessing.dummy

多线程:同一个时间片只能执行一个线程,没法充分利用CPU多核资源(只能作到并发,不能作到并行)

 

协程:操做系统和CPU不认识协程,是由程序员经过代码逻辑控制。
特色是在单线程下执行多个任务,且不须要经过操做系统切换(没有切换开销,也不须要处理锁),执行效率高。

Python: gevent ,猴子补丁(Python代码在执行网络IO阻塞时,会自动切换协程)

协程:适用于密集网络I/O任务

 

多进程爬虫:不合适

多线程爬虫:缺点 - 经过操做系统调度,有线程切换开销(海量URLs场景会增长CPU负载);优势 - 使用场景普遍(网络读写并发/数据库读写并发/磁盘读写并发)
协程爬虫:缺点 - gevent配合monkey.patch_all() 只能提升网络并发效率,不能处理其余并发场景;优势 - 经过程序员代码逻辑控制,不受操做系统调度,没有切换开销,下降CPU负载(处理海量URLs优点明显)

 


执行方式:
同步:执行一个任务,必须等待上一个任务完成(没有并发的爬虫)
异步:执行一个任务,没必要等待上一个任务完成(并发的爬虫)

程序状态:
阻塞:程序执行时,必须等待该任务完成,不然保持等待状态。
非阻塞:程序执行时,没必要等待该任务完成,能够继续执行下一个任务。

异步+非阻塞(效率最高):
发送请求后,没必要等待响应返回,能够继续处理其余请求发送;当处理功能挂起时,可以马上切换其余到功能继续执行。



异步网络框架 Twisted Tornada

Scrapy :请求处理模块+响应解析模块+twisted
scrapy-redis:Scrapy + Redis(在同一个数据库里处理请求去重、请求分配、数据存储)

单机爬虫:
分布式爬虫:

 

CPU -> 寄存器 -> CPU缓存L1/L2/L3 -> 内存 -> 硬盘/固态硬盘 -> 网络

 

协程:切换

三种方式实现:  1. yield   2.greenlet   3. gevent

1.yield

做用:

挂起当前函数 将后面表达式的值 返回到调用生成器的地方
接收数据 并唤醒当前函数 而且紧接着上次运行的地址继续执行

2.greenler

greenlet(函数)  建立协程

gr2.switch()切换到gr2执行

 

 

协程是python个中另一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为须要的资源)

通俗的理解:在一个线程中的某个函数,能够在任何地方保存当前函数的一些临时变量等信息,而后切换到另一个函数中执行,注意不是经过调用函数的方式作到的,而且切换的次数以及何时再切换到原来的函数都由开发者本身肯定

  建立并执行协程

  阻塞等待协程运行完成 .join()

  阻塞等待全部协程退出 .join_all()

  monkey.patch_all()做用是将rece, recefrom, time.sleep, accept进行破解, 不会阻塞等待, 在调用时能够切换到别的任务继续执行.

  注意:join,join_all做用保持主进程存活

 

简单总结

  • 进程是资源分配的单位
  • 线程是操做系统调度的单位
  • 进程切换须要的资源很最大,效率很低
  • 线程切换须要的资源通常,效率通常
  • 协程切换任务资源很小,效率高
  • 多进程、多线程根据cpu核数不同多是并行的 也多是并发的。协程的本质就是使用当前进程在不一样的函数代码中切换执行,能够理解为并行。 协程是一个用户层面的概念,不一样协程的模型实现多是单线程 也多是多线程。
相关文章
相关标签/搜索