多线程:
多线程的作用 :也是用于提高程序的效率
多进程:
1.核心是多道技术 (把内存分成 几块)
2.通过 本质上就是切换 加 保存状态
3. 当程序 IO 操作较多 可以提高程序效率
多线程
什么是多线程
程序的执行线路
相当于与一条流水线,其包含了程序的具体执行步骤
如果我们把操作系统比喻为一个工厂,进程就是车间,线程就是流水线
线程和进程的关系
进程中包含了运行该程序需要的所有资源
* 进程是一个资源单位,线程是CPU的最小执行单位*
每一个进程一旦被创建,就默认开启了一条线程,称之为主线程
一个进程可以包含多个线程
进程包含线程 而 线程依赖进程
为啥使用线程
是为了提高程序的使用效率
为何不用多进程提高效率? 是因为进程对操作系统的资源耗费非常高
线程是如何提高效率 的?(多线程提高效率的原理)
默认情况下 每个程序都有且只有一个主线程序,执行代码时如果遇到了io 操作系统会立即切换到其他应用程序,这就降低了当前应用程序的效率
对于CPU而言 只要线程可以被执行 所以CPU切换时在不同线程之间进行切换 ,开启多线程如何提高效率?假设 只有两个线程,每个线程都被切换到的概率是二分之一,如果左边的应用程序开启三条子线程,对于左边的应用程序被切换到的概率为三分之二
多线程可以使用CPU在一个进程内切换,从而提高CPU的占用率
如何使用
两种开启线程的方式
1.实例化 Thread类
2.继承 Threa 类 覆盖run 方法
什么情况下因该开启多线程
当程序中遇到 IO 的时候
当程序中纯计算任务时 也无法提高效率
进程和线程的区别
1 进程对于操作系统的资源耗费非常高,而线程相反非常低(比进程低10-100倍)
2.在同一个进程中,多个线程之间资源是共享的
#开启线程的第一种方式
from threading import Thread
#from multiprocessing import Process (对比进程)
def task():
print ("thread running)
t1 = Thread (target = task)
t1 . start()
print ("over")
#第二种方式
class MyThread (thread):
def run(self):
print ("子线程 running......")
MyThread().start()
print ("over2")
线程对比进程
#对比进程启动时间
from multiprocessing import Process
def task():
print ("threading running")
if __name __ =='__main__':
t1 = process(target = task)
t1.start()
print ("over")
from multiprocessing import Process
from threading import Tread
import time
def task():
# print ("子进程任务“)
pass
#100个进程时间统计
#if __name__ =='___main__':
start = time.time()
ps = []
for i in range(100):
p = Process(target = task)
p . start()
ps.append (p)
for p in ps:
p.join()
print (time.time()-start)
#100个线程
start = time.time()
ts = []
for i in range(100):
t = Thread(target = task)
t.start()
ts.append(t)
for t in ts:
t .join()
print(time.time()-start)
#线程间资源共享
from threading import Thread
x = 100
def task():
print ("run")
global x
x = 0
t= Thread(target = task)
t.start()
t.join()
print (x)
print ("over")
守护线程
守护线程
守护线程会在所有非守护线程结束后结束
当所有非线程结束后 守护线程也跟着结束了
#进程 守护进程会在被守护进程死亡跟着死亡
同一个进程 可以有多个守护进程
form threading import Thread
import time
def task():
print("sub thread run...")
time.sleep(3)
print ("sub thread over....")
t = Thread (target = task)
t.setDaemon(True)
t.start()
t = Thread(target = task)
t.setDaemon(True)
t.start()
print ("over")
from threading import Thread
import time
def task():
print ("子线程运行。。”)
time.sleep(1)
print ("子线程结束“)
t = Thread(target = task)
t.setDaemon (True)
t.start()
#time.sleep(0.1)
print ("over")
线程中常用属性
from threading import Thread,current_thread,enumerate,active_count
import os
def task():
print("running")
print (active_count())
t1 = Thread (target = task)
t1.start()
#获取所有线程对象列表
print(enumerate)
#获取当前线程对象
print(current_thread())
#获取当前正在运行的线程个数
print(active_count())
线程互斥互锁
什么时候用锁 当多个进程或多个线程需要同时修改同一份数据时,可能会造成数据的错乱,所以必须得加锁
import time
from threading import Thread,Lock
lock = Lock()
def task():
lock.acquire()
global a #在局部修改全局变量时 需要使用global
temp = a-1
time.sleep(0.01)
a = temp
lock.release()
ts = []
for i in range(100):
t =Thread (target = task)
t.start()
ts.append(t)
for t in ts:
t.join()
型号量
其实也是一种锁 ,特点是可以设置一个数据可以被几个线程(进程)共享
与普通锁的区别
普通锁一旦加锁 则意味着这个数据在同一时间只能被一个线程使用
信号量 可以让这个数据在同一时间只能被多个线程使用
使用场景,可以限制一个数据被同时访问的次数,保证程序正常运行
from threading import Semaphre,Thread,current_thread
import time,random
sem = Semaphore(3)
def task ():
sem.acquire()
print ("%s run...." %current_thread())
time.sleep(3)
sem.release()
for i in range(10):
t = Thread(target = task)
t.start()
守护进程的使用
生产者与消费者模型
吃热狗 与 做热狗
import time,random
from multiprocessing import Process,JoinableQueue
def eat_hotdog(name,q):
while True:
res = q.get()
print("%s 吃了%s" %(name,res))
time.sleep(random.randint(1,2))
q.task_done() #记录已经被处理的数据的数量
def make_hotdog(name,q):
for i in range (1,6):
time.sleep(random.randint(1,2))
print("%生产了第%s个热狗”%(name,i)
res = "%s 的%s个热狗” %(name ,i)
q.put(res)
if __name__ == '__main__':
q = JoinableQueue()
#生产者1
c1 = Process(target = make_hotdog,args =("万达热狗店“,q)
c1.start()
#生产者2 c2= Process(target = make_hotdog,args =("宝山热狗店“,q)
c2.start()
# 消费者
p2 = process(target = eat_hotdog,args = ("李亚光”,q)
p2.start()
#首先保证生产者全部生产完成
c1.join()
c2.join()
#保证队列中的数据全部被处理了 q.join() #明确生产方已经不会再生产数据了