python程序 创建多线程过程详解
一、python线程的模块
1.1thread和threading模块
thread模块提供了基本的线程和锁的支持
threading提供了更高级别、功能更强的线程管理的功能。
1.2Queue模块
Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构。
1.3注意模块的选择
- 避免使用thread模块
- 因为更高级别的threading模块更为先进,对线程的支持更为完善
- 而且使用thread模块里的属性有可能会与threading出现冲突;
- 其次低级别的thread模块的同步原语很少(实际上只有一个),而threading模块则有很多;
- 再者,thread模块中当主线程结束时,所有的线程都会被强制结束掉,没有警告也不会有正常的清除工作,至少threading模块能确保重要的子线程退出后进程才退出。
注意:thread模块不支持守护线程,当主线程退出时,所有的子线程不论它们是否还在工作,都会被强行退出。而threading模块支持守护线程,守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求它就在那等着,如果设定一个线程为守护线程,就表示这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。
二、Threading模块
multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍(官方链接)
三、通过Threading.Thread类来创建线程
3.1创建线程的方式一
1.直接通过Threading.Thread来创建
fromthreadingimportThread importtime deftask(name): print(f'子线程{name}isrunning') time.sleep(1) print(f'子线程{name}isend') #因为创建线程不需要重新开辟内存空间,所以不用写main,创建线程只是单独把启动线程函数里面的代码拿出来用 t=Thread(target=task,args=('Cecilia陈',)) t.start() print('主线程结束')
子线程Cecilia陈isrunning
主线程结束
子线程Ceciliaisend
3.2创建线程的方式二
2.通过自定义类来继承Thread类来创建线程
fromthreadingimportThread importtime classMyDic(Thread,name): def__init__(self,name) super().__init__() self.name=name defrun(self): print(f'子线程{name}isrunning') time.sleep(1) print(f'子线程{name}isend') t=Mydic('Cecilia陈') t.start() print('主进程结束')
线程Cecilia陈start
主进程
线程Cecilia陈end
四、多线程和多进程的比较
4.1pid的比较
fromthreadingimportThread frommultiprocessingimportProcess importtime importos deftask(name): print(f'子线程{name}isrunning') time.sleep(1) print(f'子线程{name}isend') print(f'子线程{name}的pid:{os.getpid()}') deftask1(name): print(f'进程{name}isrunning') time.sleep(1) print(f'进程{name}isend') print(f'进程的{name}pid:{os.getpid()}') if__name__=='__main__': #part1:在主进程下开启多个线程,每个线程都跟主进程的pid一样 t=Thread(target=task,args=('Cecilia陈',)) t.start() t.join() print(f'主线程的pid:{os.getpid()}') #开多个进程,每一个进程的pid号都不一样 p=Process(target=task1,args=('xichen',)) p1=Process(target=task1,args=('xixi',)) p.start() p1.start() p.join() p1.join() print(f'主进程的pid:{os.getpid()}')
子线程Cecilia陈isrunning
子线程Cecilia陈isend
子线程Cecilia陈的pid:10892
主线程的pid:10892
进程xixiisrunning
进程xichenisrunning
进程xichenisend
进程xixiisend
进程的xichenpid:6844
进程的xixipid:13700
主进程的pid:10892
4.2线程和进程开启效率的较量
fromthreadingimportThread frommultiprocessingimportProcess importtime deftask(name): print(f'{name}isrunning') time.sleep(2) print(f'{name}isend') if__name__=='__main__': t=Thread(target=task,args=('子线程',)) p=Process(target=task,args=('子进程',)) t.start() #p.start() print('主')
1.开启线程的速度:
子线程isrunning
主
子线程isend
2.开启进程的速度:
主
子进程isrunning
子进程isend
4.3内存数据共享问题
fromthreadingimportThread frommultiprocessingimportProcess importtime,os x=100 deftask(): globalx x=50#此时线程是在拿全局的x的值 print(os.getpid())#因为开启线程是不需要操作系统给线程分配内存空间的,所以线程用的是它当前所在的进程的进程号 if__name__=='__main__': #线程 t=Thread(target=task) t.start() time.sleep(2) print(x)#50,这里说明线程他是共享他所在进程下的所有资源,对资源进行一系列的操作 print(os.getpid()) #进程 #p=Process(target=task) #p.start() #print(x)#这里的x还是主进程的x100
五、Thread类的其他方法
Thread实例对象的方法:
- isAlive():返回线程是否活动的。
- getName():返回线程名。
- setName():设置线程名。
threading模块提供的一些方法:
- threading.currentThread():返回当前的线程变量。
- threading.enumerate():返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
- threading.activeCount():返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
5.1代码实例
fromthreadingimportThread,currentThread,enumerate,activeCount importtime deftask(): print('子线程start') time.sleep(2) print('子线程end') print(enumerate())#返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 print(currentThread(),'子线程')#返回当前的线程变量 print(activeCount()) if__name__=='__main__': t1=Thread(target=task) t2=Thread(target=task) t1.start() t2.start() t2.setName('Cecilia陈') print(t2.getName())#得到t2的线程名字,是我们设置好的Cecilia陈 print(t1.getName())#得到t1的线程名子Thread-1 print(t1.is_alive())#True
5.2join方法
fromthreadingimportThread importtime deftask(): print('子线程start') time.sleep(2) print('子线程end') t=Thread(target=task) t.start() t.join()#等待子线程运行结束 print('主线程')
六、多线程实现socket
6.1服务端
importsocket fromthreadingimportThread socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) socket.bind(('192.168.11.78',8004)) socket.listen(5) defaction(conn,addr): whileTrue: try: msg=(conn.recv(1024)).decode('utf8').upper() print(f'客户端{addr}发送的数据为:{msg.lower()}') print(f'向客户端{addr}发送数据为',msg) conn.send(msg.encode('utf8')) except: break if__name__=='__main__': print('等待客户端连接:') whileTrue: try: conn,addr=socket.accept() print(f'客户端已连接{addr}') t=Thread(target=action,args=(conn,addr)) t.start() except: print(f'客户端{addr}断开连接!!') break
6.2客户端
importsocket client=socket.socket() client.connect(('192.168.11.78',8004)) whileTrue: msg=input('输入:') ifmsg=='q': break client.send(msg.encode('utf8')) flag=client.recv(1024) print('接收服务端的数据为:',flag.decode('utf8'))
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。