什么是线程:
在一个进程中,默认就有一个线程。将进程比喻成工厂车间的话,线程就相当于车间里的一条流水线。进程负责将资源整合到一起,而线程才是cpu上面的执行单位。
多线程:
一个进程中存在多个线程,多个线程共享该进程中的地址空间,相当于车间内的多条流水线,共享车间内的所有资源。
进程和线程的区别:
线程共享创建它的进程的地址空间。而进程有自己单独的地址空间。
线程共享其进程资源,而进程完全copy其父进程资源。
进程中的线程与线程可以直接通信,进程必须依赖进程间通信与同级进程通信。
创建线程的开销远远小于进程,不用重复开辟内存空间。
开启线程的两种方式:
#方式一
from threading importThreaddeftalk():print("%s is running"%os.getpid())if __name__ == '__main__':
t= Thread(target=talk)
t.start()print('主')#方式二
from threading importThreadimportosclassMyThread(Thread):def __init__(self,name):
super().__init__()
self.name=namedefrun(self):print("pid %s name [%s] is running"%(os.getpid(),self.name))if __name__ == '__main__':
t= MyThread("egon")
t.start()print("主",os.getpid())
创建线程的两种方式
同一进程下开启多线程和多进程的区别:
from multiprocessing importProcessfrom threading importThreaddeftalk():
start=time.time()print("%s is running"%os.getpid())print(time.time()-start)if __name__ == '__main__':#多进程,每个进程都有不同的ip
t1 = Process(target=talk)
t2= Process(target=talk)
t3= Process(target=talk)
t1.start()
t2.start()
t3.start()#多线程,每个线程的ip都和主线程一样
t4 = Thread(target=talk)
t5= Thread(target=talk)
t6= Thread(target=talk)
t4.start()
t5.start()
t6.start()print('主',os.getpid())
View Code
练习:
#服务端
importthreadingfrom socket import *phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
phone.bind(("192.168.19.115",8888))
phone.listen(5)deftalk(conn,addr):whileTrue:try:
data= conn.recv(1024)if not data:breakconn.send(data.upper())exceptException:breakconn.close()if __name__ == '__main__':whileTrue:
conn,addr=phone.accept()
p= threading.Thread(target=talk,args=(conn,addr))
p.start()#客户端
from socket import *c=socket(AF_INET,SOCK_STREAM)
c.connect(('192.168.19.115',8888))whileTrue:
msg= input(">>>:".strip())if not msg:continuec.send(msg.encode("utf-8"))
data= c.recv(1024)print(data.decode('utf-8'))
c.close()
多线程实现并发
from threading importThread
input_lis=[]
format_lis=[]deftalk():whileTrue:
msg= input(">>>:").strip()if not msg:continueinput_lis.append(msg)defformat():whileTrue:ifinput_lis:
res=input_lis.pop()
format_lis.append(res.upper())defsave():
with open("db.txt",'a')as f:whileTrue:ifformat_lis:
f.write("%s\n"%(format_lis.pop()))
f.flush()if __name__ == '__main__':
t1= Thread(target=talk)
t2= Thread(target=format)
t3= Thread(target=save)
t1.start()
t2.start()
t3.start()
模拟文件存储的过程
线程的其它属性和方法:
from threading importThread,currentThread,activeCountimportos,time,threadingdeftalk():print("%s is running"%(currentThread().getName()))if __name__ == '__main__':
t= Thread(target=talk)
t= Thread(target=talk,name = "egon")
t.start()print(t.name)#线程名
print(t.getName())print(t.is_alive())print(currentThread().getName())#默认线程名
print(threading.enumerate())#返回一个列表,同activeCount
time.sleep(3)print(t.is_alive())#是否存活
print("主",activeCount())#个数
其它属性和方法
守护线程:
无论是守护进程还是守护线程,都要遵循:守护进程(线程)会随着主进程(线程)运行结束而销毁。
对进程来说:运行结束就是主进程代码运行结束
对线程来说:运行结束必须等到所有的非守护线程运行结束后,主线程才算运行结束,因为主线程的结束以为这该进程的结束,进程的整体资源都将被回收。
from threading importThread,currentThreadimporttimedeftalk1():
time.sleep(10)#这里如果是小于或等于非守护进程的睡眠时间,将会执行下面代码print("%s is running"%currentThread().getName())#10秒时间足以让主线程和非守护线程执行结束,这句不会打印,随着主线程结束而结束
deftalk2():
time.sleep(2)print("%s is running"%currentThread().getName())if __name__ == '__main__':
t1= Thread(target=talk1)
t2= Thread(target=talk2)
t1.daemon=True
t1.start()
t2.start()print('主程序执行完成')#守护线程随着主线程的结束而结束,注意主线程是当所有的非守护线程结束后才会结束
全局解释锁GIL:
GIL的本质还是一把互斥锁,所有的互斥锁的本质都是一样,那就是将并发转成串行,以此来控制同一时间内共享数据只能被一个任务修改,从而保护数据的安全性。
保护不同的数据安全,就应该加不同的锁
GIL是把同一进程内,多个线程争抢一把锁,保证同一时刻只有一个线程在运行
在线程执行过程中与I/O,运行时间过长的时候会强制释放GUL供其他线程使用。知道该线程再次抢到GUL,基于上次继续运行。
from threading importThread,Lockimporttime
n= 100
defwork():globaln
tem=n
time.sleep(0.5)
n= tem-1
if __name__ == '__main__':
mutex=Lock()
t_lis=[]
s=time.time()for i in range(100):
t= Thread(target=work)
t_lis.append(t)
t.start()for t int_lis:
t.join()print("%s:%s"%(time.time()-s,n))#0.5403599739074707:99执行了100次但是结果是99,出现数据错乱
from threading importThread,Lockimporttime
n= 100
defwork():
mutex.acquire()globaln
tem=n
time.sleep(0.5)
n= tem-1mutex.release()if __name__ == '__main__':
mutex=Lock()
t_lis=[]
s=time.time()for i in range(100):
t= Thread(target=work)
t_lis.append(t)
t.start()for t int_lis:
t.join()print("%s:%s"%(time.time()-s,n))#50.05104112625122:0加上应用层互斥锁,运行时间长,数据安全
View Code