大纲:
1.初始线程和进程
2.多线程和多进程
3.创建多线程
4.计算多线程耗时和join方法
5.守护线程
6.线程锁
7.信号量
8.事件
一.初识线程和进程
1.线程概念
线程是程序执行的最小单位。是进程的一个实体。
2.线程特点
a.在同一进程中的各个线程,都可以共享该进程所拥有的资源。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
b.在一个进程中的多个线程之间,可以并发执行,同样,不同进程中的线程也能并发执行
c.程是能独立运行的基本单位,因而也是独立调度和分派的基本单位
d.线程中的实体(数据,程序,实体控制块-TCB)基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。
3.进程概念
一个具有一定独立功能的程序(程序是指令的集合,是静态的,不能够单独的运行)的的一次运动活动。
程序以一个整体的形式暴露给操作系统,里面包含各种资源的调用,内存的管理,网络接口的调用,对各种资源管理的集合就是进程
4.进程的特点
a.进程是一个实体
b.进程是一个运行着的程序。是动态的
5.进程和线程之间的区别?
a.线程共享内存空间,而进程的内存是相对独立的。
b.同一个进程间的线程可以相互交流,但是两个进程想实现通讯必须要有一个中间代理
c.创建新线程很简单,但是创建新的进程是对父进程的再一次的克隆
d.一个线程可以控制和操作同一个进程里的其他线程,但是一个进程只能操作子进程。
二.多线程和多进程
一个任务就是一个进程,比如说我们打开一个qq聊天就是执行了一个进程,我们可以在打开qq聊天的同时,打开word打字,可以浏览网页,这时我们就是执行了多个进程。在打开word的任务里面,可以执行编辑,打印等一系列子任务,那么每一个子任务都是一个线程。python中一个进程至少有一个线程。那么怎样实现多任务并发呢?
a.同时执行多个进程
b.同时执行多个线程
c.同时执行多个进程+多个线程
无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行,那么我们上面说的都是废话?python怎样实现多任务并发的呢。操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
三.创建多线程
两种方式:
1.直接创建
import threading,time#创建线程使用模块threading
def run(n):
print("task:",n)
time.sleep(2)
t1=threading.Thread(target=run,args=("t1",))#创建线程t1
t2=threading.Thread(target=run,args=("t2",))#创建线程t2
t1.start()#开启线程t1
t2.start()
#执行结果t1和t2同时执行完成,是多线程并行
run("t1")
run("t2")
#执行结果,先执行了任务t1,等待了2s后再执行的t2,是多线程串行
2.通过调用的方式创建—面向对象的方法
import threading
class MyThread(threading.Thread):#继承了threading.Thread
def __init__(self,n):
super(MyThread,self).__init__()#继承
self.n=n
def run(self):#start中就调用了run方法执行
print("task:",self.n)
t1=MyThread("t1")
t2=MyThread("t2")
t1.start()
t2.start()
四.计算多线程运行的时间实例及jion方法的使用
import threading,time#创建线程使用模块threading
def run(n):
print("task:",n)
time.sleep(2)
print("每次是什么进程",threading.current_thread())#子线程
print("当前活跃线程个数", threading.active_count())#当前活跃线程个数 16
start_time=time.time()
obj_list=[]#建立一个空列表来存放线程
for i in range(15):#利用循环的方式创建15个线程
t=threading.Thread(target=run,args=("t-%s"%i,))
t.start()
obj_list.append(t)#将运行的15个线程依次加入到列表里面
for t in (obj_list):#循环线程的实例列表,等待所有线程执行完毕
t.join()#join是什么意思?
end_time=time.time()
print("cost:",(end_time-start_time))
#执行结果---cost: 2.00500011444
print("查看当前是什么线程",threading.current_thread())#查看当前是什么线程 <_MainThread(MainThread, started)>
上面的程序引入了一个join的方法
1.join()
join的作用是保证当前线程执行完成后,再执行其它线程。join可以有timeout参数,表示阻塞其它线程timeout秒后,不再阻塞。
import threading,time
def sayhello(num):
print("hello world")
time.sleep(2)
start_time=time.time()
for i in range(3):
t=threading.Thread(target=sayhello,args=("t-%s"%i,))
t.start()
t.join()
print("main process over")
end_time = time.time()
print("cost:",(end_time-start_time))
#加了join程序变成了串行----cost: 6.00499987602
#去掉jion-----cost: 0程序全部执行完成后等待2s退出
五.守护线程
什么是守护线程?如果设置了守护线程证明这个线程就变得不重要。假如非守护线程执行完毕退出,整个程序就全部退出
,那么不用等守护线程执行完毕。
怎样设置守护线程:在t.start()之前设置t.setDaemon(True)就表示这个线程“不重要”。这里默认是false
下面我们就用具体的代码验证一下这个结论
import threading,time
def run():
print("start run")
time.sleep(1)
print("end run")
print("start main")
t=threading.Thread(target=run)
t.start()
print("end main")
执行结果:等待所有进程执行完毕,程序才退出
start main
start run
end main
end run
import threading,time
def run():
print("start run")
time.sleep(1)
print("end run")
print("start main")
t=threading.Thread(target=run)
t.setDaemon(True)
t.start()
print("end main")
执行结果:
start main
end main
start run
六.线程锁(又叫互斥锁–mutex)
线程是相互独立存在的,但是同一个进程下的线程是共享这个进程的同一片资源的,加入发生三个线程同时修改进程的同一份数据就会发生不可预期的结果。这个时候就引入了线程锁,在执行线程的共享数据池之前先申请一把锁,保证同一时间只有一个线程修改同一份数据。
不知为何,在python加锁和不加锁执行效果一样,建议在python2中执行以下程序比较
1.加锁
import threading,time
num=0
lock=threading.Lock()#创建锁
def add():
global num
lock.acquire()#获取锁 锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,
# 则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。
num=num+1
lock.release()#释放锁
obj_list=[]
for i in range(10):
t=threading.Thread(target=add)
t.start()
obj_list.append(t)
for i in obj_list:
t.join()#等待所有的子线程执行完毕,主线程才可以向下执行
print("num:",num)
2.不加锁
import threading,time
num=0
#lock=threading.Lock()#创建锁
def add():
global num
#lock.acquire()#获取锁 锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,
# 则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。
num=num+1
#lock.release()#释放锁
obj_list=[]
for i in range(10):
t=threading.Thread(target=add)
t.start()
obj_list.append(t)
for i in obj_list:
t.join()#等待所有的子线程执行完毕,主线程才可以向下执行
print("num:",num)
七.线程–信号量(semaphore )
信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。互斥锁同一时间只允许一个线程修改共享数据,但是信号量允许一定数量的线程同时修改数据。
import threading,time
def run(n):
sema.acquire()#获取信号量锁
time.sleep(2)
print("run thread:%s"%n)
sema.release()()#释放信号量锁
if __name__=='__main__':
sema=threading.BoundedSemaphore(5)#创建信号量,最多允许5个进程同时执行
for i in range(22):
t=threading.Thread(target=run,args=(i,))
t.start()
执行结果
八.线程–事件
线程的event是为了实现多个线程间的通讯
enent有三个函数,事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
e=threading.event()
e.wait()等待标志位被设定,阻塞
e.set()标志位设定,恢复正常运行
e.clear()标志位被清空
举例:红绿灯
import time,threading
event = threading.Event()
def lighter():
count=0
event.set()
while True:
if count>=0 and count<10:
event.set()#设置标志位,变为绿灯允许通行
print("greenlight is on...")
elif count>=10 and count<20 :
event.clear()#清空标志位,变为红灯禁止通行
print("redlight is on...")
else:
count=0#重置,进入循环
time.sleep(5)
count+=1
light = threading.Thread(target=lighter)
light.start()
def car():
while True:
time.sleep(5)
if event.isSet():
print("car can run")
else:
print("light turn on red ,stop")
car1=threading.Thread(target=car)
car1.start()