线程
程序:是指令的集合,是进程运行的静态描述文本
进程:是程序的一次执行活动
进程是资源分配的最小单位
线程:cup调度的最小单位
线程是属于进程的
线程的特点:
1.轻量级进程
2.独立调度和分配的基本单位
3.共享进程资源
4.可并发执行
为什么会有线程:
基于网络上的服务,我们希望我们的应用在同一时刻能做更多的事情,
并且还能共享一段数据
线程:
线程是进程的一部分
一个进程必须依赖进程存在
一个进程内至少有一个线程
进程中默认存在线程 主线程
也可以在一个进程中开辟多个子线程来完成更多的事情
多个进程和多个线程都是可以利用多核的
但是因为GIL(全局解释器锁)在cpython中不可以利用多核
GIL全局解释器锁 是Cpython解释器中的
关于创建线程的模块 threading thead 和Queue
线程创建(threading模块):
创建线程的两种方式:
第一种:
from threading import Thread def func(name): print('这是子线程,%s'%name) if __name__ == '__main__': t = Thread(target=func,args=('智障',)) t.start() print('这是主线程') 结果: 这是子线程,智障 这是主线程
第二种:
from threading import Thread class MyThread(Thread): def __init__(self,name): super().__init__() self.name = name def run(self): print('这是%s的子线程'%self.name) if __name__ == '__main__': t = MyThread('智障') t.start() print('主线程') 结果: 这是智障的子线程 主线程
用面向对象的方法创建线程:
Thread中,没有__init__方法,所以必须要用super()
必须要有run方法
多线程和多及进程的比较:
from multiprocessing import Process from threading import Thread import os def func(): print(os.getpid()) if __name__ == '__main__': p1 = Process(target=func) p2 = Process(target=func) p1.start() p2.start() p1.join() p2.join() print('主线程',os.getpid()) t1 = Thread(target=func) t2 = Thread(target=func) t1.start() t2.start() t1.join() t2.join() print('主线程', os.getpid()) 结果: 6072 3080 主线程 2440 2440 2440 主线程 2440
在主进程开启多个线程,每个线程的都跟主进程的pid一样
在多进程中开启多个进程,每个进程的id都不一样
内存数据的共享:
from multiprocessing import Process from threading import Thread import os a = 100 def func(): global a a = 0 if __name__ == '__main__': p = Process(target=func) p.start() p.join() print(a) # 多进程中不改变a的值,说明多进程中数据不共享的 t = Thread(target=func) t.start() t.join() print(a) #多线程改变a的值,说明线程中数据是共享的
Thread的其他方法:
Thread实例对象的方法:
t.isAlive():返回线程是否活的
t.getName():返回线程名
t.setName():设置线程名
threading模块提供的一些方法:
threading.currentThread():返回当前的线程变量
threadiing.enumerate():返回一个包含正在运行的线程的list
正在运行指的是线程启动后,结束前不包括启动前和终止后的线程
join方法和进程的一样
守护线程:
无论是线程还是进程,都遵循:守护进程/线程等主线程/进程运行完毕后进行销毁,
需要强调的是:代码运行完毕,并不是指终止运行
1.对进程来说:运行完毕指的是主进程代码运行完毕
2,对线程来说:运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕
from threading import Thread import time def func(name): print('%s正在吃饭'%name) if __name__ == '__main__': t1 = Thread(target=func,args=('alex',)) t2 = Thread(target=func,args=('wusir',)) t1.setDaemon(True) t1.start() t2.start() time.sleep(1)
GIL锁:只能保证同一时刻,不可能有两个线程同时执行cpu指令
互斥锁:保证同一时刻只能一个线程对数据进程操作,间接保证了数据的安全
from threading import Thread,Lock n = 100 def func(lock): global n with lock: n = n - 1 if __name__ == '__main__': lock = Lock() for i in range(100): t = Thread(target=func,args=(lock,)) t.start() t.join() print(n)
如果不加互斥锁 数据可能会发生改变
线程队列:
import queue # import queue 和进程Queue用法一样 queue.Queue()#先进先出 queue.LifoQueue()#后进先出 queue.PriorityQueue()#优先级队列需要两个参数第一个是顺序 第二个是值
线程池(concurrent.futures):
concurrent.futures高度封装异步调用接口
ThreadPoolExecutor:线程池 提供异步调用
ProcessPoolExecutor:进程池 提供异步调用
方法:
submit()异步提交
map()取代for循环提交submit
shutdown相当于进程池中的pool.close和pool.join
result 取得结果
add_done_callback()回调函数
用for循环提交任务:
import time from concurrent.futures import ThreadPoolExecutor def func(i): time.sleep(1) print('in son thread',i) tp = ThreadPoolExecutor(4) for i in range(20): tp.submit(func,i) tp.shutdown() print('所有的人都执行完了') # 注意: #shutdown不能写在for循环内 # 接收参数的位置不用写成元祖的形式了
用map提交任务:
import time from concurrent.futures import ThreadPoolExecutor def func(i): time.sleep(1) print('in son thread',i) tp = ThreadPoolExecutor(4) tp.map(func,range(20)) tp.shutdown() print('所有的人都执行完了')
回调函数:add_done_callback
import time from concurrent.futures import ThreadPoolExecutor def foo(ret): print(ret.result())#用result()才能从未来对象中取得结果 def func(i): time.sleep(0.1) # print('in son thread',i) return 'i'*i tp = ThreadPoolExecutor(4) for i in range(20): ret = tp.submit(func,i) ret.add_done_callback(foo) tp.shutdown()