多线程
一.什么是线程?
线程就是程序的执行线路
相当于一条流水线,其包含了程序的具体执行步骤
操作系统比喻为一个工厂,进程就是车间,线程就是流水线
线程和进程的关系?
进程中包含了运行该程序的所有资源
进程是一个资源单位,线程cpu的最小执行单位
每个进程一旦被创建,就默认开启了一条线程,称之为主线程
一个进程可以包含多个线程
进程包含线程而线程依赖于进程
为什么使用线程?
为了提高程序效率
不用进程是因为进程对操作系统的资源消耗非常高
线程是如何提高效率?
多线程可以使cpu在一个进程内进行切换,从而提高cpu占用率
多线程提高工作效率原理?
默认情况下每个进程都有且只有一个主线进程,执行代码时如果遇到IO操作系统就会切换到其他应用程序,这就降低了当前应用程序的效率.
如果含有多线程,cpu切换是在不同线程之间进行切换,加入只有两个线程,每个线程被切换到的几率为二分之一,如果一个的应用程序开启了子线,总共就有了三条线程,那么该应用程序被切到的几率就变成了三分之二!
什么时候开启多线程?
当程序中遇到IO的时候
如何使用?
两种开启线程的方式
①实例化Thread类
from threading import Thread def task(): print('你好!') t = Thread(target=task) t.start() print('over')
②继承Thread类覆盖run方法
from threading import Thread class Mythread(Thread): def run(self): print('你好!') t = Mythread() t.start() print('over')
①进程对操作系统的资源消耗非常高,而线程非常低(比进程低10-100倍)
#100个进程时间统计
from multiprocessing import Process
import time
def task():
pass
if __name__ == '__main__':
start_time = 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_time)
结果:6.828858137130737
#100个线程时间统计
from threading import Thread
import time
def task():
pass
start_time = 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_time)
结果:0.01562190055847168
②在同一个进程多个线程之间资源是共享的
from threading import Thread a = 0 def task(): print('run....') global a a = 100 t = Thread(target=task) t.start() t.join() print(a) print('over') 结果: run.... 100 over
守护线程会在所有非守护线程结束后结束
同一个进程可以有多个守护线程
from threading import Thread import time def task(): print('子线程开始!') time.sleep(1) print('子线程结束!') t = Thread(target=task) #t.daemon = True t.setDaemon(True) t.start() print('over') #结果: 子线程开始! over
三.线程中常用的属性
from threading import Thread import os def task(): print('running') print(os.getpid()) t1 = Thread(target=task) t1.start() t2 = Thread(target=task) t2.start() 结果: running 1056 running 1056 在不同线程中获取到的进程ID是相同的
from threading import Thread def task(): print('running') t1 = Thread(target=task) t1.start() print(t1.is_alive()) print(t1.isAlive()) 结果:True True 这两个是一样的
from threading import Thread,current_thread,enumerate,active_count def task(): print('running') print(current_thread()) #获取当前线程对象 print(active_count()) #当前正在运行的线程数量 结果:2 t1 = Thread(target=task) t1.start() print(t1.getName()) #获取该线程的名字 print(enumerate()) #获取所有线程对象 print(active_count()) #当前正在运行的线程数量 结果:1
什么时候用锁?
当多个进程或者多个线程需要同时修改同一份数据的时候,可能会造成数据的错乱,所以必须加锁
from threading import Thread,Lock import time lock = Lock() a = 100 def task(): lock.acquire() global a 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() print(a)
信号量:其实也是一把锁,特点是可以设置一个数据可以被几个线程(进程)共享
与普通锁的区别:
普通锁一旦加锁,意味着数据在同一时间只能被一个线程使用
信号量:可以让这个数据再同一时间被多个线程使用
应用场景:可以限制一个数据在同一时间被访问的次数,保证程序正常运行
from threading import Thread,Semaphore,current_thread import time 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()
进程中 队列守护进程的应用 生产者消费者模型 :思聪吃热狗
from multiprocessing import Process,JoinableQueue import time,random def make_hotdog(name,q): for i in range(1,6): time.sleep(random.randint(1,2)) print('%s烹饪出来了第%s个热狗'%(name,i)) res = '%s的第%s个热狗'%(name,i) q.put(res) def eat_hotdog(name,q): while True: res = q.get() print('%s吃了%s'%(name,res)) time.sleep(random.randint(1,2)) q.task_done() #记录已经被处理的数据的数量 if __name__ == '__main__': q = JoinableQueue() #生产者1 m1 = Process(target=make_hotdog,args=('万达热狗店',q)) m1.start() #生产者2 m2 = Process(target=make_hotdog,args=('京东热狗店',q)) m2.start() #消费者 e = Process(target=eat_hotdog,args=('思聪',q)) e.daemon = True #设置消费者为守护进程 e.start() #保证生产者全部生产完成 m1.join() m2.join() #保证队列中的数据全部被处理了 q.join() #明确生产方已经不会再产生数据了