6.线程、进程、协程基础篇

1.进程是资源分配的最小单位,拥有自己独立的栈和堆,进程间资源不共享,进程是由操作系统调度,一个进程可以开启多个线程;

在python中multiprocess模块提供了Process类,实现进程相关功能。

简单实现:

# -*- coding: utf-8 -*-
#__author:jiangjing
#date:2018/2/3

from multiprocessing import Process

def func(index):
    print('Process %d' % index)
if __name__ == '__main__':
    for i in range(4):
        p = Process(target=func, args=(i,))
        p.start()

2.线程是cpu调度的最小单位,拥有自己独立的栈和共享的堆,也是由操作系统调度

python中的 GIL(Global Interpreter Lock),全局解释器锁,首先需要明确的是:GIL并不是python这门语言的特性,它是在CPython解释器引入的一个概念,而python又有很多解释器,CPython解释器是其中最流行的一个,看下图,当python解释器是 CPython时,执行流程为:

(1)线程1获得GIL,线程2没有获得GIL则不能继续执行;

(2)线程1往下走经过操作系统,操作系统经过调度,让cpu1执行;

(3)线程1释放GIL,线程2获得,则线程2按照上面步骤走,循环往复。

结论:当python解释器是CPython时,由于GIL的存在,所以只会有一个线程在执行,不能利用多核cpu,CPython的GIL是历史遗留的一个问题。

                                 python代码执行流程图

python中的threading模块实现了Thread类

简单实现:

方式一:

# -*- coding: utf-8 -*-
#__author:jiangjing
#date:2018/2/3

import threading
import time

def func(index):
    time.sleep(1)
    print('Thread %d' % index)

for i in range(10):
    t = threading.Thread(target=func, args=(i,))
    t.start()

方式二:

# -*- coding: utf-8 -*-
#__author:jiangjing
#date:2018/2/3

import threading
class MyThreading(threading.Thread):

    def __init__(self,func,arg):
        super(MyThreading,self).__init__()
        self.func = func
        self.arg = arg

    def run(self):
        self.func(self.arg)

def func(index):
    print('Threading %d' % index)

for i in range(10):
    obj = MyThreading(func, i)
    obj.start()

3.协程拥有独立的栈和共享的堆,由程序员在代码中自己调度,通过2的讲解,知道了在CPython解释器中每一时刻只会有一个线程在跑,利用不了多核cpu,但是还存在多线程切换的消耗,所以就出了协程,协程是在一个线程上跑,把一个线程分解成多个“微线程”,实现类似多线程的效果,并且节省了多线程时线程切换的时间。

第三方模块greenlet和gevent实现协程

greenlet实现:


# -*- coding: utf-8 -*-
#__author:jiangjing
#date:2018/2/3

def
test1(): print(12) gr2.switch() print(34) gr2.switch() def test2(): print(56) gr1.switch() print(78) gr1 = greenlet(test1) gr2 = greenlet(test2) gr1.switch() 输出为: 12 56 34 78

gevent实现:

# -*- coding: utf-8 -*-
#__author:jiangjing
#date:2018/2/3

from gevent import monkey
monkey.patch_all() #windows下提升io阻塞敏感度,碰到io阻塞快速切换
import gevent
import requests
import time

def func(url):
    print('url: %s' % url)
    resp = requests.get(url)
    data = resp.text
    print('%d bytes received from %s.' % (len(data), url))

start_time = time.time()
gevent.joinall([
        gevent.spawn(func, 'http://www.cnblogs.com/jiangjing/'),
        gevent.spawn(func, 'https://www.cnblogs.com/'),
        gevent.spawn(func, 'https://www.cnblogs.com/f-ck-need-u/p/8409723.html'),
        gevent.spawn(func, 'http://www.cnblogs.com/f-ck-need-u/p/7048359.html'),
        gevent.spawn(func, 'https://www.python.org/'),
])
end_time = time.time()
print('consume time is %d' % (end_time - start_time))

输出为:
url: http://www.cnblogs.com/jiangjing/
url: https://www.cnblogs.com/
url: https://www.cnblogs.com/f-ck-need-u/p/8409723.html
url: http://www.cnblogs.com/f-ck-need-u/p/7048359.html
url: https://www.python.org/
11658 bytes received from http://www.cnblogs.com/jiangjing/.
40828 bytes received from https://www.cnblogs.com/.
30753 bytes received from https://www.cnblogs.com/f-ck-need-u/p/8409723.html.
33181 bytes received from http://www.cnblogs.com/f-ck-need-u/p/7048359.html.
48890 bytes received from https://www.python.org/.
consume time is 1

不使用协程,使用单线程串行执行对比:

# -*- coding: utf-8 -*-
#__author:jiangjing
#date:2018/2/3

from gevent import monkey
monkey.patch_all() #windows下提升io阻塞敏感度,碰到io阻塞快速切换
import gevent
import requests
import time

def func(url):
    print('url: %s' % url)
    resp = requests.get(url)
    data = resp.text
    print('%d bytes received from %s.' % (len(data), url))

start_time = time.time()
urls = ['http://www.cnblogs.com/jiangjing/', 'https://www.cnblogs.com/',
        'https://www.cnblogs.com/f-ck-need-u/p/8409723.html',
        'http://www.cnblogs.com/f-ck-need-u/p/7048359.html',
        'https://www.python.org/']
for url in urls:
    func(url)
end_time = time.time()
print('consume time is %d' % (end_time - start_time))

输出为:
url: http://www.cnblogs.com/jiangjing/
11658 bytes received from http://www.cnblogs.com/jiangjing/.
url: https://www.cnblogs.com/
40822 bytes received from https://www.cnblogs.com/.
url: https://www.cnblogs.com/f-ck-need-u/p/8409723.html
30753 bytes received from https://www.cnblogs.com/f-ck-need-u/p/8409723.html.
url: http://www.cnblogs.com/f-ck-need-u/p/7048359.html
33181 bytes received from http://www.cnblogs.com/f-ck-need-u/p/7048359.html.
url: https://www.python.org/
48890 bytes received from https://www.python.org/.
consume time is 2

结论:使用协程执行速度更快

原文地址:https://www.cnblogs.com/jiangjing/p/8409802.html