zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    周末之个人杂想(十三)
    PowerTip of the DaySorting Multiple Properties
    PowerTip of the DayCreate Remoting Solutions
    PowerTip of the DayAdd Help to Your Functions
    PowerTip of the DayAcessing Function Parameters by Type
    PowerTip of the DayReplace Text in Files
    PowerTip of the DayAdding Extra Information
    PowerTip of the DayPrinting Results
    Win7下IIS 7.5配置SSAS(2008)远程访问
    PowerTip of the DayOpening Current Folder in Explorer
  • 原文地址:https://www.cnblogs.com/jiangjing/p/8409802.html
Copyright © 2011-2022 走看看