什么是线程:
顾名思义就是一条流水线的工作过程,so,进程只是用来把资源集中到一起(进程只是一个资源单位或者说资
源集合)而线程才是cpu上的执行单位
DUOXIANCHENG
在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间
线程和进程的区别:
线程创建速度快,开销小,多线程共享一个进程的地址空间
开启线程的两种方式:
通常本人喜欢用第一种
from threading import Thread import time def sayhi(name): time.sleep(2) print('%s say hello' %name) if __name__ == '__main__': t=Thread(target=sayhi,args=('egon',)) t.start() print('主线程')
from threading import Thread import time class Sayhi(Thread): def __init__(self,name): super().__init__() self.name=name def run(self): time.sleep(2) print('%s say hello' % self.name) if __name__ == '__main__': t = Sayhi('egon') t.start() print('主线程')
IPC:进程之间的通信,两种方式,一个是管道,一个是队列
在一个进程下开启多个线程和在一个进程下开启多个字进程的区别
from threading import Thread
from multiprocessing import Process
import os
def work():
print('hello')
if __name__ == '__main__':
#在主进程下开启线程
t=Thread(target=work)
t.start()
print('主线程/主进程')
'''
打印结果:
hello
主线程/主进程
'''
#在主进程下开启子进程
t=Process(target=work)
t.start()
print('主线程/主进程')
'''
打印结果:
主线程/主进程
hello
'''
from threading import Thread from multiprocessing import Process import os def work(): print('hello',os.getpid()) if __name__ == '__main__': #part1:在主进程下开启多个线程,每个线程都跟主进程的pid一样 t1=Thread(target=work) t2=Thread(target=work) t1.start() t2.start() print('主线程/主进程pid',os.getpid()) #part2:开多个进程,每个进程都有不同的pid p1=Process(target=work) p2=Process(target=work) p1.start() p2.start() print('主线程/主进程pid',os.getpid())
from threading import Thread
from multiprocessing import Process
import os
def work():
global n
n=0
if __name__ == '__main__':
# n=100
# p=Process(target=work)
# p.start()
# p.join()
# print('主',n) #毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100
n=1
t=Thread(target=work)
t.start()
t.join()
print('主',n) #查看结果为0,因为同一进程内的线程之间共享进程内的数据
练习:三个任务,一个接受用户输入,一个将用户输入的内容格式化成大写,一个将格式化后的结果存入文件
from threading import Thread msg_l=[] format_l=[] def talk(): while True: msg=input('>>: ').strip() if not msg:continue msg_l.append(msg) def format_msg(): while True: if msg_l: res=msg_l.pop() format_l.append(res.upper()) def save(): while True: if format_l: with open('db.txt','a',encoding='utf-8') as f: res=format_l.pop() f.write('%s ' %res) if __name__ == '__main__': t1=Thread(target=talk) t2=Thread(target=format_msg) t3=Thread(target=save) t1.start() t2.start() t3.start()
用于课堂练习的代码
from threading import Thread,currentThread,activeCount import os,time,threading def talk(): time.sleep(2) print('%s is running' %currentThread().getName()) if __name__ == '__main__': t=Thread(target=talk) t.start() t.join() print('主')
from threading import Thread,Lock import time n=100 def work(): # mutex.acquire() global n temp=n time.sleep(0.5) n=temp-1 # mutex.release() if __name__ == '__main__': mutex=Lock() t_l=[] s=time.time() for i in range(100): t=Thread(target=work) t_l.append(t) t.start() for t in t_l: t.join() print('%s:%s' %(time.time()-s,n))
from threading import Thread
input_l=[]
format_l=[]
def talk():
while True:
msg=input('>>: ')
if not msg:continue
input_l.append(msg)
def format():
while True:
if input_l:
res=input_l.pop()
format_l.append(res.upper())
def save():
with open('db.txt','a') as f:
while True:
if format_l:
f.write('%s
' %(format_l.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 import Thread, currentThread
from multiprocessing import Process
import os, time, threading
def talk1():
time.sleep(10)
print('%s is running' % currentThread().getName())
def talk2():
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('主线程', os.getpid())
from threading import Thread,currentThread,activeCount
import os,time,threading
def talk():
print('%s is running' %currentThread().getName())
if __name__ == '__main__':
# t=Thread(target=talk,name='egon')
t=Thread(target=talk)
t.start()
# print(t.name)
# print(t.getName())
# print(t.is_alive())
# print(currentThread().getName())
print(threading.enumerate())
time.sleep(3)
print(t.is_alive())
print('主',activeCount())
同步锁:
需要注意的点:
1.线程抢的是GIL锁,GIL锁相当于执行权限,拿到执行权限后才能拿到互斥锁Lock,其他线程也可以抢到GIL,但如果发现Lock仍然没有被释放则阻塞,即便是拿到执行权限GIL也要立刻交出来
2.join是等待所有,即整体串行,而锁只是锁住修改共享数据的部分,即部分串行,要想保证数据安全的根本原理在于让并发变成串行,join与互斥锁都可以实现,毫无疑问,互斥锁的部分串行效率要更高
GIL VS Lock
锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据
结论:保护不同的数据用不同的锁
GIL是解释器级别的,保护解释器级别的数据,比如垃圾回收的数据
Lock保护用户自己开发的应用程序的数据
所有线程抢的是GIL锁或者说抢的是执行权限,
拿到执行权限开始执行,然后加了一把Lock,还没有执行完毕
线程1抢到GIL锁,拿到执行权限,开始执行,然后加了一把Lock,还没有执行完毕,即线程1还未释放Lock,有可能线程2抢到GIL锁,开始执行,执行过程中发现Lock还没有被线程1释放,于是线程2进入阻塞,被夺走执行权限,有可能线程1拿到GIL,然后正常执行到释放Lock。。。这就导致了串行运行的效果
死锁与递归锁
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
from threading import Thread,Lock import time mutexA=Lock() mutexB=Lock() class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): mutexA.acquire() print('