zoukankan      html  css  js  c++  java
  • python--第十天总结(线程、进程和协程)

    Python线程

    Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
      
    def show(arg):
        time.sleep(1)
        print 'thread'+str(arg)
      
    for i in range(10):
        t = threading.Thread(target=show, args=(i,))
        t.start()
      
    print 'main thread stop'

    上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

    更多方法:

    • start            线程准备就绪,等待CPU调度
    • setName      为线程设置名称
    • getName      获取线程名称
    • setDaemon   设置为后台线程或前台线程(默认)
                         如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                          如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
    • join              逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
    • run              线程被cpu调度后执行Thread类对象的run方法

    线程锁

    由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。所以,可能出现如下问题:

    未使用锁:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
    
    gl_num = 0
    
    def show(arg):
        global gl_num
        time.sleep(1)
        gl_num +=1
        print gl_num
    
    for i in range(10):
        t = threading.Thread(target=show, args=(i,))
        t.start()
    
    print 'main thread stop'

    使用锁:

    #!/usr/bin/env python
    #coding:utf-8
       
    import threading
    import time
       
    gl_num = 0
       
    lock = threading.RLock()
       
    def Func():
        lock.acquire()
        global gl_num
        gl_num +=1
        time.sleep(1)
        print gl_num
        lock.release()
           
    for i in range(10):
        t = threading.Thread(target=Func)
        t.start()

    event

    python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

    事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。

    • clear:将“Flag”设置为False
    • set:将“Flag”设置为True
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
    import threading
     
     
    def do(event):
        print 'start'
        event.wait()
        print 'execute'
     
     
    event_obj = threading.Event()
    for i in range(10):
        t = threading.Thread(target=do, args=(event_obj,))
        t.start()
     
    event_obj.clear()
    inp = raw_input('input:')
    if inp == 'true':
        event_obj.set()

    Python 进程

     1 from multiprocessing import Process
     2 import threading
     3 import time
     4   
     5 def foo(i):
     6     print 'say hi',i
     7   
     8 for i in range(10):
     9     p = Process(target=foo,args=(i,))
    10     p.start()

    注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。

    进程数据共享

    进程各自持有一份数据,默认无法共享数据

    #!/usr/bin/env python
    #coding:utf-8
     
    from multiprocessing import Process
    from multiprocessing import Manager
     
    import time
     
    li = []
     
    def foo(i):
        li.append(i)
        print 'say hi',li
      
    for i in range(10):
        p = Process(target=foo,args=(i,))
        p.start()
         
    print 'ending',li
    
    进程间默认无法数据共享
    如果想让进程之间数据共享,就得有个特殊的数据结构

     1 #方法一,Array
     2 from multiprocessing import Process,Array
     3 temp = Array('i', [11,22,33,44]) #这里的i是C语言中的数据结构,其他的类型见下面
     4  
     5 def Foo(i):
     6     temp[i] = 100+i
     7     for item in temp:
     8         print i,'----->',item
     9  
    10 for i in range(2):
    11     p = Process(target=Foo,args=(i,))
    12     p.start()
    13  
    14 #方法二:manage.dict()共享数据
    15 from multiprocessing import Process,Manager
    16  
    17 manage = Manager()
    18 dic = manage.dict()
    19  
    20 def Foo(i):
    21     dic[i] = 100+i
    22     print dic.values()
    23  
    24 for i in range(2):
    25     p = Process(target=Foo,args=(i,))
    26     p.start()
    27     p.join()
    'c': ctypes.c_char,  'u': ctypes.c_wchar,
    'b': ctypes.c_byte,  'B': ctypes.c_ubyte,
    'h': ctypes.c_short, 'H': ctypes.c_ushort,
     'i': ctypes.c_int,   'I': ctypes.c_uint,
     'l': ctypes.c_long,  'L': ctypes.c_ulong,
     'f': ctypes.c_float, 'd': ctypes.c_double
    
    类型对应表

    当创建进程时(非使用时),共享数据会被拿到子进程中,当进程中执行完毕后,再赋值给原值。

    进程锁实例:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from multiprocessing import Process, Array, RLock
    
    def Foo(lock,temp,i):
        """
        将第0个数加100
        """
        lock.acquire()
        temp[0] = 100+i
        for item in temp:
            print i,'----->',item
        lock.release()
    
    lock = RLock()
    temp = Array('i', [11, 22, 33, 44])
    
    for i in range(20):
        p = Process(target=Foo,args=(lock,temp,i,))
        p.start()
    

    进程池

    进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

    进程池中有两个方法:

    • apply
    • apply_async
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 from  multiprocessing import Process,Pool
     4 import time
     5   
     6 def Foo(i):
     7     time.sleep(2)
     8     return i+100
     9   
    10 def Bar(arg):
    11     print arg
    12   
    13 pool = Pool(5)
    14 #print pool.apply(Foo,(1,))
    15 #print pool.apply_async(func =Foo, args=(1,)).get()
    16   
    17 for i in range(10):
    18     pool.apply_async(func=Foo, args=(i,),callback=Bar)
    19   
    20 print 'end'
    21 pool.close()
    22 pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。

    协程

    线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

    协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

    协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;

    greenlet

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
     
    from greenlet import greenlet
     
     
    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()

    gevent

    import gevent
     
    def foo():
        print('Running in foo')
        gevent.sleep(0)
        print('Explicit context switch to foo again')
     
    def bar():
        print('Explicit context to bar')
        gevent.sleep(0)
        print('Implicit context switch back to bar')
     
    gevent.joinall([
        gevent.spawn(foo),
        gevent.spawn(bar),
    ])

    遇到IO操作自动切换:

    from gevent import monkey; monkey.patch_all()
    import gevent
    import urllib2
    
    def f(url):
        print('GET: %s' % url)
        resp = urllib2.urlopen(url)
        data = resp.read()
        print('%d bytes received from %s.' % (len(data), url))
    
    gevent.joinall([
            gevent.spawn(f, 'https://www.python.org/'),
            gevent.spawn(f, 'https://www.yahoo.com/'),
            gevent.spawn(f, 'https://github.com/'),
    ])
  • 相关阅读:
    Druid 使用 Kafka 将数据载入到 Kafka
    Druid 使用 Kafka 数据加载教程——下载和启动 Kafka
    Druid 集群方式部署 —— 启动服务
    Druid 集群方式部署 —— 端口调整
    Druid 集群方式部署 —— 配置调整
    Druid 集群方式部署 —— 配置 Zookeeper 连接
    Druid 集群方式部署 —— 元数据和深度存储
    Druid 集群方式部署 —— 从独立服务器部署上合并到集群的硬件配置
    Druid 集群方式部署 —— 选择硬件
    Druid 独立服务器方式部署文档
  • 原文地址:https://www.cnblogs.com/wjx1/p/5115639.html
Copyright © 2011-2022 走看看