博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程,进程 ,队列 基本用法总结
阅读量:7249 次
发布时间:2019-06-29

本文共 8157 字,大约阅读时间需要 27 分钟。

一、线程(线程是最小的工作单位,同一进程内的线程共享资源)

创建线程:threading模块

创建一个线程:threading.Thread(target=函数名,args=(参数,) )  *这里的args后面必须是元祖,而且当括号内是一个参数是,第一个参数后加逗号

我们利用threading模块创建的线程都是子线程,因为解释器在工作的时候会创建一个主线程来进行工作,我们自己创造的线程都是子线程

import threadingimport  timedef f1(a1,a2):    time.sleep(2)    print("456")t = threading.Thread(target = f1,args = (124,111,))t.setDaemon(True)#不等待子线程执行完成t.start()t1 = threading.Thread(target = f1,args = (124,111,))t1.setDaemon(True)#不等待子线程执行完成t1.start()t2 = threading.Thread(target = f1,args = (124,111,))t2.setDaemon(True)#不等待子线程执行完成t2.start() 注:主线程是代码从上往下执行(我们看不见),setDaemon默认为False,即主线程等待子线程执行完,一起退出,如果我们设置t2.setDaemon(True),即主线程不等子线程执行完就退出

t.join() :逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

t.join(参数) :中的参数表示最多的等待时间,如果函数的执行时间小于等待时间,那么就等待你函数的执行时长,如果等待时间大于函数执行时间,那么等待你参数时间后就不等待了

t.setDaemon(True)#是决定是否等待子线程执行完成后再退出,加上表示不等待子线程执行完就退出,不加表示等待子线程后再退出

import threadingimport  timedef f1(a1,a2):    time.sleep(3)    print("456")t = threading.Thread(target = f1,args = (124,111,))t.setDaemon(True)#不等待子线程执行完成t.start()t.join(2)print("222") 222 注:主线程执行时间是3,而我等待时间是2,所以在我等待的时间内子线程没有执行,所以只执行主线程就退出
import threadingimport  timedef f1(a1,a2):    time.sleep(3)    print("456")t = threading.Thread(target = f1,args = (124,111,))t.start()t.join(2)print("222")222456 注:主线程执行时间是3,而我等待时间是2,所以在我等待的时间内子线程没有执行,所以我先执行主线程的再执行你子线程的

 二、 threading.Event

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

  • Event.wait([timeout]) : 堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)。
  • Event.set() :将标识位设为Ture
  • Event.clear() : 将标识伴设为False。
  • Event.isSet() :判断标识位是否为Ture。
import threadingimport timedef do(event):    time.sleep(1)    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()       #设置为Falseinp = input('input:')if inp == 'true':    event_obj.set()     #设置为Ture

三、线程锁

由于同一进程下的多个线程共享同一内存地址的资源,所以就有可能出现不同的线程修改同一数据,导致脏数据(不正确的数据)的出现,所以我们应该在一个线程修改的时候加一把锁,等这个线程修改完后下一线程再来修改,所以就引进了线程锁的概念

import threadingimport timeglobals_num = 0lock = threading.RLock()def Func():    lock.acquire()  # 获得锁    global globals_num    globals_num += 1    time.sleep(1)    print(globals_num)    lock.release()  # 释放锁for i in range(5):    t = threading.Thread(target=Func)    t.start()注:每一个线程执行的时候都加一把锁,就不会出现脏数据,只有前面一个线程执行完,解锁以后后面一个线程才能获得变量并对其进行修改,所以输出顺序是每一个输出都等待1s,而且输出顺序递增

4、队列

特性:先进先出,单项队列只能一进一出

创建队列 :queue.Queue(参数)参数表示队列的容量即最多容纳的个数

q = queue.Queue(maxsize=0)  # 构造一个先进显出队列,maxsize指定队列长度,为0 时,表示队列长度无限制。q.join()    # 等到队列为空的时候,在执行别的操作q.qsize()   # 返回队列的大小 (不可靠)q.empty()   # 当队列为空的时候,返回True 否则返回False (不可靠)q.full()    # 当队列满的时候,返回True,否则返回False (不可靠)q.put(item, block=True, timeout=None) #  表示往队列里面放q.get(block=True, timeout=None) # 表示从队列里面取值,如果队列里面没值是会一直等即阻塞 q.put_nowait(item) #   等效于 put(item,block=False)q.get_nowait() #    等效于 get(item,block=False) 表示如果队列里面没值时不等

生产者--消费者 模型

import queueimport threadingmessage = queue.Queue(10)def producer(i):  #每一个生成的线程都一直往队列里面放对应生成的值    while True:        message.put(i)def consumer(i):  ##每一个生成的线程都一直从队列里面获取生成的值    while True:        msg = message.get()        print(msg)for i in range(12):    t = threading.Thread(target=producer, args=(i,)) #生成12个线程共同执行producer函数    t.start()for i in range(10):    t = threading.Thread(target=consumer, args=(i,))  # #生成10个线程共同执行consumer函数    t.start()

 

import queueimport threadingmessage = queue.Queue(10)def producer(i):           message.put(i)  #每一个线程把各自生成的数放到队列中,一共放了5个def consumer(i):        msg = message.get() #一共有10个线程过来获取,只获取了5个就没有了,剩下的就一直等待        print(msg)for i in range(5):    t = threading.Thread(target=producer, args=(i,))    t.start()for i in range(10):    t = threading.Thread(target=consumer, args=(i,))    t.start()
import queueimport threadingmessage = queue.Queue(10)def producer(i):        message.put(i)  #每一个线程把各自生成的数放到队列中,一共放了5个def consumer(i):        msg = message.get_nowait()  #一共有10个线程过来获取,只获取了5个就没有了,不等待直接退出        print(msg)for i in range(5):    t = threading.Thread(target=producer, args=(i,))    t.start()for i in range(10):    t = threading.Thread(target=consumer, args=(i,))    t.start()

 五、进程

创建进程:multiprocessing模块

创建一个进程:multiprocessing.Process(target=函数名,args=(参数,) ) *这里的args后面必须是元祖,而且当括号内是一个参数是,第一个参数后加逗号

在windos下不支持fork()的创建,如果想用进程是必须把对进程的操作写在 if  __name__=="__main__"下,在linux下不用

我们利用multiprocessing模块创建的线程都是子进程,因为解释器在工作的时候会创建一个主线程(包含在主进程中)来进行工作,我们自己创造的进程都是子进程

import  timeimport multiprocessingdef f1(a1,a2):    time.sleep(2)    print("456")if __name__ == '__main__':    t = multiprocessing.Process(target = f1,args = (124,111,))    t.daemon = True#不等待子进程执行完成    t.start()    t1 = multiprocessing.Process(target = f1,args = (124,111,))    t1.daemon = True#不等待子进程执行完成    t1.start()    print("end") end 注:主线程是代码从上往下执行(我们看不见),daemon默认为False,即主叫进程等待子进程执行完,一起退出,如果我们设置t1.daemon = True,即主进程不等待子进程执行完就退出

 

import  timeimport multiprocessingdef f1(a1,a2):    time.sleep(2)    print("456")if __name__ == '__main__':    t = multiprocessing.Process(target = f1,args = (124,111,))    t.daemon = True#不等待子进程执行完成    t.start()    print("111")    t.join(1)    print("end") 111 end 注:先执行print("111") 在等待1函数没执行就不等待了,直接执行print("end")

 六、

由于多个进程有自己的内存资源,所以修改只是修改了各自的东西,所以不存在线程锁的概念

import multiprocessingli = []def f(a):    li.append(a)  #不同的进程往不同的进程里面的li中添加元素    print(li)if __name__ =="__main__":    for a in range(5):        t =  multiprocessing.Process(target=f,args=(a,))        t.start() [0] [2] [1] [3] [4]

进程间的数据共享 

如果我们想让俩个不同的进程共同修改同一内容的话,即如果你真有需要 要共享数据, multiprocessing提供了两种方式。

1、Array

from multiprocessing import Process,Arraytemp = 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、Manager

import timefrom  multiprocessing import Process,Managerdef f(i,dic):    dic[i] = 100 + i    print(dic)if __name__  == "__main__":    manage = Manager()    dic = manage.dict()    for i in range(5):        p = Process(target= f,args=(i,dic,))        p.start()        p.join()  #必须要加,要不就找不到文件了 {0: 100} {0: 100, 1: 101} {0: 100, 1: 101, 2: 102} {0: 100, 1: 101, 2: 102, 3: 103} {0: 100, 1: 101, 2: 102, 3: 103, 4: 104}

 进程池

 由于线程和进程并不是越多越好,而是应该创建最优的数量,所以就有了进程池的概念,创建一个进程池并不会立即创建进程,而是根据需要从进程池里面取的时候才会创建进程

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

进程池中有两个方法:

  • apply 
  • apply_async
from  multiprocessing import Process,Poolimport timedef Foo(i):    time.sleep(2)    return i+100def Bar(arg):    print(arg)if __name__ == "__main__":    pool = Pool(5)    #print pool.apply(Foo,(1,))    #print pool.apply_async(func =Foo, args=(1,)).get()    for i in range(10):        pool.apply_async(func=Foo, args=(i,),callback=Bar)    print('end')    pool.close()    pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。 注:申请一个进程执行Foo方法,Foo方法没执行完,Bar方法永远不触发,只有Foo方法执行完了,才触发Bar方法,并将其返回值赋值给Bar方法的参数

  回调函数:用于验证主函数是否执行完

apply :1、从进程池中申请进程

     2、每次申请的一个线程总都自带一个join

     3、特点是申请一个执行一个,完了再申请再执行

     4、因为每一个申请的进程都有一个join,所以任务执行过程是排队进行的

     5、申请的次数和进程池中进程的数量没有关系,因为我每次申请一个,等执行完第一个再执行下一个

from multiprocessing import Poolimport timedef f1(a):    time.sleep(1)    print(a)if __name__ == "__main__":    pool = Pool(5)    for i in range(6):        T = pool.apply(func=f1,args=(i,))        print("222222222222")022222222222212222222222222222222222222322222222222242222222222225222222222222

apply_async:1、从进程池中申请进程

        2、每次申请的一个线程都没有join,所以申请以后不等待执行就申请下一个

        3、如果申请的数量大于进程池中进程的数量,则每次申请的进程数就是进程池中的进程数,等待执行完毕,进程回到进程池后才可以从新申请

        4、每一个任务都是并发执行的,而且可以设置回调函数

        5、进程池的执行默认不等待子进程的执行,所以,如果主进程执行完毕后子进程没执行完就直接退出了,所以我们应该在主进程执行后加一个join,这样主进程                                    就会等待子进程执行完毕后一起退出(自己瞎猜的O(∩_∩)O哈哈~)

from multiprocessing import Poolimport timedef f1(a):    time.sleep(1)    print(a)if __name__ == "__main__":    pool = Pool(5)    for i in range(9):        pool.apply_async(func=f1,args=(i,))        print("222222222222")    pool.close()     pool.join() #进程池的方法222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222012345678

 

posted on
2017-05-14 19:05 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/yezuhui/p/6853407.html

你可能感兴趣的文章
个人笔记:LINUX下MAIL通知维护
查看>>
Azure国际版VM密码重置(Portal)
查看>>
libvirt kvm云主机监控
查看>>
Apache配置静态缓存
查看>>
URL欺骗
查看>>
Zabbix图像集中展示Graphtrees开源
查看>>
《聚爆Implosion》性能精析:这是我们测过性能最棒的手游,没有之一!
查看>>
Linux GPT分区格式磁盘的相关操作
查看>>
DCD DSR DTR RTS CTS 的含义
查看>>
OpenTest:教你在自动化脚本中增加选择文件的支持
查看>>
关于安装ASPNetExtMVC2008.exe 后不出现MVC项目的问题
查看>>
强烈推荐ISCSI target和initiator软件
查看>>
企业服务经验总结--服务器安全细则2
查看>>
python中时间的加n和减n运算
查看>>
软件开发人员应具备的基本素质 !!!
查看>>
无线运维——J2ME和WAP运维方式的优缺点
查看>>
生产环境Shell脚本Ping监控主机是否存活(多种方法)
查看>>
关于SQLServer2000中触发器的使用——多行数据提交
查看>>
commons-fileupload 1.3.1 上传测试
查看>>
红帽集群套件RHCS四部曲(概念篇)
查看>>