zoukankan      html  css  js  c++  java
  • 第二十五篇、进程和线程

    一、进程与线程之间的关系

    线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。

     1 优点:同时利用多个cpu,能够同时进行多个操作 2 缺点:耗费资源(重新开辟内存空间) 

     1 优点:共享内存,IO操作时候,创造并发操作 2  缺点:抢占资源 

    进程不是越多越好,cpu个数=进程个数

    线程也不是越多越好,具体案例具体分析,请求上下文切换耗时

    1 1、计算机执行程序任务的最小单元是线程
    2 2、所有的操作都不是利用cpu的,IO操作不是利用cpu的
    3 所以
    4 IO密集型(不用cpu)
    5 用多线程
    6 计算密集型(用cpu)
    7 用多进程

    二、使用线程

    1、

        import threading
            def f0():
                pass
            def f1(a1,a2):
                time.sleep(10)
                f0()
            t1 = threading.Thread(target=f1,args=(123,111,))
            t1.start()
            t1.join()
    
            t = threading.Thread(target=f1,args=(123,111,))
            t.setDaemon(True)
            t.start()
            t = threading.Thread(target=f1,args=(123,111,))
            t.setDaemon(True)
            t.start()
    线程代码

    以上创建的线程叫做3个子线程

    上面三个线程执行完毕之后就夯住了,然后等待10秒结束

    2、

    上面的setDeamon如果为True的时候就可以设置主线程是否为后台线程。如果是,那么主线程执行完毕,就不会等待子线程是否执行完毕,直接结束

    主线程等待,子线程执行

    3、

    t.join():这个线程执行完毕之后再往下执行,如果里面有参数n,表示这个线程最多等待n秒就往下执行,如果n大于主线程时间a,那么就最多等待a秒

     1 t.start() : 激活线程,
     2 
     3 t.getName() : 获取线程的名称
     4 
     5 t.setName() : 设置线程的名称 
     6 
     7 t.name : 获取或设置线程的名称
     8 
     9 t.is_alive() : 判断线程是否为激活状态
    10 
    11 t.isAlive() :判断线程是否为激活状态
    12 
    13 t.setDaemon() 设置为后台线程或前台线程(默认:False);通过一个布尔值设置线程是否为守护线程,必须在执行start()方法之后才可以使用。如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止;如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
    14 
    15 t.isDaemon() : 判断是否为守护线程
    16 
    17 t.ident :获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None。
    18 
    19 t.join() :逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
    20 
    21 t.run() :线程被cpu调度后自动执行线程对象的run方法
    更多方法

    三、线程锁threading.RLock和threading.Lock

    我们使用线程对数据进行操作的时候,如果多个线程同时修改某个数据,可能会出现不可预料的结果,为了保证数据的准确性,引入了锁的概念

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    import threading
    import time
    glo_num = 0
    
    lock = threading.RLock()
    
    def func():
        lock.acquire() #获的锁
        global glo_num
        glo_num +=1
        time.sleep(1)
        print(glo_num)
        lock.release()#释放锁
    
    for i in range(10):
        t = threading.Thread(target=func)
        t.start()
    
    结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    代码

    threading.RLock和threading.Lock 的区别

    RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。 如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。

    所以

    lock不好,建议用Rlock

    四、线程事件threading.Event

    Event是线程间通信最间的机制之一:一个线程发送一个event信号,其他的线程则等待这个信号。用于主线程控制其他线程的执行。 Events 管理一个flag,这个flag可以使用set()设置成True或者使用clear()重置为False,wait()则用于阻塞,在flag为True之前。flag默认为False。

    #!/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 = input("input:")
    if inp == "True":
        event_obj.set()  #让等边绿
    
    当用户输入true的时候,才能让车路过
    红绿灯例子代码
    Event.wait([timeout]) : 堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)。
    Event.set() :将标识位设为Ture
    Event.clear() : 将标识伴设为False。
    Event.isSet() :判断标识位是否为Ture。
    方法

    五、队列和生产者消费者模式

    1 Queue 就是对队列,它是线程安全的
    2 举例来说,我们去肯德基吃饭。厨房是给我们做饭的地方,前台负责把厨房做好的饭卖给顾客,顾客则去前台领取做好的饭。这里的前台就相当于我们的队列。(先进先出)
    3 这个模型也叫生产者-消费者模型。
    4 python2中的queue是大写开头,3里面是小写
    #!/usr/bin/env python
    import Queue
    import threading
    
    
    message = Queue.Queue(10)
    
    
    def producer(i):
        print(“aa”)
    #while True:
            message.put(i)
    
    
    def consumer(i):
        print(“aa”)
        #while True:
            msg = message.get()
    
    
    for i in range(12):
        t = threading.Thread(target=producer, args=(i,))
        t.start()
    
    for i in range(10):
        t = threading.Thread(target=consumer, args=(i,))
        t.start()
    代码例子
    import queue
    
    q = queue.Queue(maxsize=0)  # 构造一个先进显出队列,maxsize指定队列长度,为0 时,表示队列长度无限制。
    
    q.join()    # 等到队列为kong的时候,在执行别的操作
    q.qsize()   # 返回队列的大小 (不可靠)
    q.empty()   # 当队列为空的时候,返回True 否则返回False (不可靠)
    q.full()    # 当队列满的时候,返回True,否则返回False (不可靠)
    q.put(item, block=True, timeout=None) #  将item放入Queue尾部,item必须存在,可以参数block默认为True,表示当队列满时,会等待队列给出可用位置,
                             为False时为非阻塞,此时如果队列已满,会引发queue.Full 异常。 可选参数timeout,表示 会阻塞设置的时间,过后,
                              如果队列无法给出放入item的位置,则引发 queue.Full 异常
    q.get(block=True, timeout=None) #   移除并返回队列头部的一个值,可选参数block默认为True,表示获取值的时候,如果队列为空,则阻塞,为False时,不阻塞,
                          若此时队列为空,则引发 queue.Empty异常。 可选参数timeout,表示会阻塞设置的时候,过后,如果队列为空,则引发Empty异常。
    q.put_nowait(item) #   等效于 put(item,block=False)
    q.get_nowait() #    等效于 get(item,block=False)
    方法

    方法中的put(往队列里面放值)

    get方法(从队列里面取值)

    队列的例子:12306网站就是内存级别的队列

    还有更好的队列,后面会说到

    六、multiprocessing模块

    multiprocessing是python的多进程管理包,和threading.Thread类似。直接从侧面用subprocesses替换线程使用GIL的方式,由于这一点,multiprocessing模块可以让程序员在给定的机器上充分的利用CPU。

    在multiprocessing中,通过创建Process对象生成进程,然后调用它的start()方法

    from multiprocessing import Process
     
    def f(name):
        print('hello', name)
     
    if __name__ == '__main__':
        p = Process(target=f, args=('bob',))
        p.start()
        p.join()
    代码

    七、进程

    import multiprocessing
    import time
    def f1(a1):
        time.sleep(2)
        print(a1)
    if __name__ == “__main__”:
    t = multiprocessing.Process(target=f1,args=(11,))
    t.deamon = True
    t.start()
    print (“end”)
    上面的是两个子进程
    1、创建进程

    创建进程windows里面运行不了,但是把进程写在if __name__ == “__main__”:里面,但是总不可能永远写在这里面,所以要写在linux中运行

    2、daemon和线程的一样,是否为后台进程True 为后台进程,即主线程执行完毕之后就不再执行其他
    
    3、join和线程类似,join这个进程执行完毕之后才往下执行

    4、进程和进程之间的数据是不能够共享的,如果一个程序能够随便进入另一个进程里面读取数据会造成混乱   如某某管家

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    from multiprocessing import Process
    import threading
    import time
    li = []
    def foo(i):
        li.append(i)
        print("say hi",li)
    if __name__ == "__main__":
        for i in range(10):
            p = Process(target=foo,args=(i,))
            p.start()
    结果:
    say hi [0]
    say hi [1]
    say hi [2]
    say hi [3]
    say hi [4]
    say hi [5]
    say hi [6]
    say hi [7]
    say hi [9]
    say hi [8]
    
    上面一个进程创建一个新的列表
    实例代码
    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    from multiprocessing import Process
    import threading
    import time
    li = []
    def foo(i):
        li.append(i)
        print("say hi",li)
    if __name__ == "__main__":
        for i in range(10):
            p = threading.Thread(target=foo,args=(i,))
            p.start()
    say hi [0]
    say hi [0, 1]
    say hi [0, 1, 2]
    say hi [0, 1, 2, 3]
    say hi [0, 1, 2, 3, 4]
    say hi [0, 1, 2, 3, 4, 5]
    say hi [0, 1, 2, 3, 4, 5, 6]
    say hi [0, 1, 2, 3, 4, 5, 6, 7]
    say hi [0, 1, 2, 3, 4, 5, 6, 7, 8]
    say hi [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    这个是一个进程里面例子

    5、一个程序之间的数据也能进行共享

    需要用到如下方法

    1、Array方法

    数组在定义的时候必须要制定长度。或者元素
    数组里面必须是统一的数据类型
    from multiprocessing import Process,Array
    tmp = Array(“i”,[11,22])  里面的参数I  指定数据类型
    关于数组的知识
    from multiprocessing import Process,Array
    temp = Array('i', [11,22,33,44])
     
    def Foo(i):
        temp[i] = 100+i
        for item in temp:
            print i,'----->',item
     
    for i in range(2):
        p = Process(target=Foo,args=(i,))
        p.start()
    代码

    2、manage.dict()共享数据

    m = Manager()  m.dict()

    from multiprocessing import Process,Manager
    def Foo(i,dic):
        dic[i] = 100+i
        print(len(dic))
    
    if __name__ == '__main__':
        manage = Manager()
        dic = manage.dict()
        for i in range(2):
            p = Process(target=Foo,args=(i,dic,))
            p.start()
            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
  • 相关阅读:
    单例模式和配置admin
    ORM单表查询,跨表查询,分组查询
    进程同步控制 Lock Semaphore Event
    创建进程和多进程 process join p.daemon terminate
    并发编程基础
    远程执行模块和黏包 socketserve hamc模块验证合法性
    网络编程之Socket
    网络基础
    del new item hash 单例模式
    面向对象进阶
  • 原文地址:https://www.cnblogs.com/pyrene/p/6471553.html
Copyright © 2011-2022 走看看