目录
3.3.5 进程与多进程-multiprocessing.Pool
1、进程与线程
1.1 定义
1.1.1 进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,正在运行的程序,是系统进行资源分配和调度的基本单。
1.1.2 线程
线程是操作系统最小的调度单位, 是一串指令的集合。线程被称为轻量级进程(Lightweight Process,LWP),是cpu调度的基本单位,组成:线程ID、当前指令指针(PC)、寄存器集合、堆栈组成 ,在单个程序中同时运行多个线程完成不同的工作,称为多线程。
1.2 线程与进程的关系
真正在cpu上运行的是线程 ,线程共享内存空间;进程的内存是独立的 ,一个线程只能属于一个进程,而一个进程可以有多个线程, 但至少有一个线程。
资源分配给进程,同一进程的所有线程共享该进程的所有资源。进程的资源是独立的,同一个进程的线程之间可以直接交流;两个进程想通信,必须通过一个中间代理来实。
创建新的线程很简单,创建一个新的进程都需要对其父进程进行一次克隆,一个线程可以控制和操作同一个进程里的其他线程,进程只能操作子进程,一个主线程改变,可能会影响其他线程,改变父进程不会影响子进程。
1.3 进程状态模型
1.4 多进程与多线程的比较
2、threading模块
1.1 功能
threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。
threading模块提供的常用类:
Thread:创建线程
Lock/RLock:互斥锁
1.2 threading——Thread
1.2.1 Thread构造方法
构造方法:
Thread(group=None, target=None, name=None, args=(), kwargs={})
- group: 线程组,目前还没有实现,库引用中提示必须是None;
- target: 要执行的方法;
- name: 线程名;
- args/kwargs: 要传入方法的参数
1.2.2 Thread实例方法
- t.name:获取或设置线程的名称
- t.getName()/setName(name): 获取/设置线程名。
- t.is_alive()、t.isAlive():判断线程是否为激活状态,返回线程是否在运行,正在运行指启动后、终止前。
- t.ident :获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None。
- t.run() :线程被cpu调度后自动执行线程对象的run方法。
- t.start(): 线程准备就绪,等待CPU调度,start会自动调用t.run()。
- t.join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout (可选参数)。
- t.setDaemon(bool): 设置是后台线程(默认前台线程(False)),(在start之前设置) 如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程和后台线程均停止。如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止。
- t.isDaemon:判断是否为后台线程。
import requests
import time
from threading import Thread
def cost(f):
# print("this is cost")
def _cost(*args, **kwargs):
start = time.time()
result = f(*args, **kwargs)
end = time.time()
print(f"执行{f.__name__}花费{end-start}s")
return result
return _cost
def get_content(url):
print("start......")
text = requests.get(url).text
time.sleep(0.5)
print("get content")
@cost
def main():
t_list = []
for i in range(5):
# get_content("https://www.baidu.com")
#创建线程
#target --》 执行要传入的方法名字, 要做什么
#args --》 指定方法需要传入的参数 元组类型
t = Thread(target=get_content,args=("https://www.baidu.com",))
t_list.append(t)
#设置为后台线程, 主线程退出,子线程也退出
#t.setDaemon(True)
#启动线程
t.start() #自动调用t.run()
# t.join()
#阻塞当前环境上下文,直到为t的线程执行完成
# [ t.join() for t in t_list]
print("end.........")
main()
输出:
start......
start......
start......
end.........
执行main花费0.0s
get contentget content
get content
get content
get content
使用自定义线程:
import threading
class MyThread(threading.Thread):
def __init__(self,num):
super().__init__()
self.num = num
def run(self):
print(f"running in numbers:{self.num}")
t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()
1.3 threading——Lock
资源总是有限的,程序运行如果对同一个对象进行操作,则有可能造成 一些异常情况,如: 数据前后读取不一致,资源的争用甚至导致死锁。
在多线程中使用lock可以让多个线程在共享资源的时候遵循一定的规则。
常见锁类型 :
- Lock()/RLock:普通锁(互斥锁) 解决资源争用,数据读取不一致等
- Semaphore :信号量最多允许同时N个线程执行内容
- Event: 事件锁 根据状态位,决定是否通过事件
- Condition: 条件
1.3.1 Lock()/RLock:普通锁(互斥锁)
解决资源争用,数据读取不一致等。
构造方法: Lock()
实例方法:
- acquire([timeout]): 尝试获得锁定。使线程进入同步阻塞状态。
- release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。
import threading
import time
num = 0
def sum_num(i):
print(f"lock start....{i}")
# lock.acquire() #获得锁
with lock:
global num
time.sleep(0.5)
num += i
print(num)
# lock.release() #释放锁
lock = threading.RLock() #互斥锁对象
for i in range(5):
t = threading.Thread(target=sum_num, args=(i,))
t.start()
输出:
lock start....2
lock start....3
lock start....4
0
1
3
6
10
Lock 原始锁:获取锁之前不做判断,直到获取到锁为止。
RLOCK 重入锁:获取锁之前先判断,如果自己有了锁,那就立即放回。
1.3.2 Semaphore :信号(信号锁)
最多允许同时N个线程执行内容