多线程与多进程,协程的理解

多线程与多进程的理解

什么是线程

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程是一个execution context(执行上下文),即一个cpu执行时所需要的一串指令。

什么是进程

进程是指一个程序在给定数据集合上的一次执行过程,是系统进行资源分配和运行调用的独立单位。可以简单地理解为操作系统中正在执行的程序。也就说,每个应用程序都有一个自己的进程。

每一个进程启动时都会最先产生一个线程,即主线程。然后主线程会再创建其他的子线程。

二者的区别

1.同一个进程中的线程共享同一内存空间,但是进程之间是独立的。
2.同一个进程中的所有线程的数据是共享的(进程通讯),进程之间的数据是独立的。
3.对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。
4.线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。
5.同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理来实现。
6.创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。
7.一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。
8.线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。

GIL

说道多进程不得不说一下Python的GIL
在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少核,同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。

GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操作cpu,只能利用GIL保证同一时间只能有一个线程拿到数据。而在pypy和jpython中是没有GIL的。

进程

Python 要进行多进程操作,需要用到muiltprocessing库,其中的Process类跟threading模块的Thread类很相似。所以直接看代码熟悉多进程。


from multiprocessing import Process

def run(num):
    print('hello  process')
    for i in range(5):
        print(num,i)
if __name__ =='__main__':
    for i in  range(5):
        proces = Process(target=run,args=(i,))#创建多个进程
        proces.start()#启动
        proces.join() #进程池中进程执行完毕再关闭,如果注释,那么程序直接关闭

线程

Python提供两个模块进行多线程的操作,分别是thread和threading,
前者是比较低级的模块,用于更底层的操作,一般应用级别的开发不常用。


import threading
def run(num):
    print('hello threading')
    for i in range(5):
        print('%s -- %d' % (threading.current_thread().name, i))#注意这里的'threading.current_thread().name'这个是获取当前正在运行的线程名字

if __name__ == '__main__':
    for i in  range(5):
        thread = threading.Thread(target=run, args=(i,))#创建多个线程
        thread .start()#启动线程

选择多进程还是多线程

CPU 密集型:程序比较偏重于计算,需要经常使用 CPU 来运算。例如科学计算的程序,机器学习的程序等。
I/O 密集型:顾名思义就是程序需要频繁进行输入输出操作。爬虫程序就是典型的 I/O 密集型程序。

如果程序是属于 CPU 密集型,建议使用多进程。而多线程就更适合应用于 I/O 密集型程序。

协程

协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时。协程,则只使用一个线程,分解一个线程成为多个“微线程”,在一个线程中规定某个代码块的执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO)。
常用第三方模块gevent和greenlet。(本质上,gevent是对greenlet的高级封装,因此一般用它就行,这是一个相当高效的模块。)

简单的协程爬虫


from urllib import  request
import  ssl
import gevent
from  gevent import  monkey

#把当前程序的所有的IO操作 单独做上标记
monkey.patch_all()
ssl._create_default_https_context = ssl._create_unverified_context

def spider(url):
    print('GET:%s' %url)
    resp = request.urlopen(url)
    print(resp)
    data = resp.read()
    f = open("test.html","wb")
    f.write(data)
    f.close()
    print("%d --------------- %s" %(len(data),url))

gevent.joinall([gevent.spawn(f,'http://www.qiushibaike.com/'),
                gevent.spawn(f,'http://news.qq.com/'),
                gevent.spawn(f,'http://www.toutiao.com/'),
                ])

协程的优点

1 : 线程在单线程下切换,减少资源消耗
2 : 无需原子操作控制流,简化编程模型
3 : 高并发,高扩展,低成本.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值