程序:是指令的集合,是进程运行的静态描述文本
进程:是程序的一次执行活动
进程是资源分配的最小单位
线程: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()