- 1、线程
- ① 函数方式创建线程
- ② 自定义类创建线程
- 2、队列
- ① 普通队列 Queue
- ② 堆栈 LifoQueue
- ③ 优先级 PriorityQueue
- 3、互斥锁
- 4、进程
- ① 函数方式创建进程
- ② 类方式创建进程
- ③ 进程中的队列
- ④ 进程间通信
- 5、 线程与进程区别
- ① 线程共享全局变量,进程不共享
- ② 所有的线程都在同一个进程中
- ③ 线程开销小,但不利于资源的管理和保护,进程相反
- 6、进程池
- ① 案例1:
- ② 进程池间通信
- 案例1:
1、线程
线程是进程的一个实体,是cpu调度和分派的基本单位。
Python中的线程是轻量级执行单元,可以在同一进程中并发执行。Python中的线程由threading模块提供支持。线程的创建可以通过直接实例化Thread类或者继承Thread类并重写run()方法来实现。
import threading # 导入线程包
def f_a(): # 创建函数a
pass
thread_1 = threading.Thread(target=f_a,args=(),kwargs={}) # 创建线程
thread_1.start() # 开始执行线程
① 函数方式创建线程
简单创建线程测试
import threading
import time
def task_1(print1):
while 1:
print(print1)
time.sleep(1)
print1 = "woshi 1111111111"
thread_1 = threading.Thread(target=task_1,args=(print1,)) # 通过 args/kwargs传入元组/字典进行传参
thread_1.start()
while 1:
print("hello")
time.sleep(1)
② 自定义类创建线程
import threading # 导入线程包
class C_1(threading.Thread): # 自定义 并继承threading.Thread类
def run(self): # 添加run()方法,start()自动调用该方法
pass
thread_1 = C_1()
thread_1.start() # 此处调用thread_1.run()方法并不能生成线程
2、队列
Python中的队列是一种数据结构,用于在多个线程之间安全地传递数据。队列的实现可以使用queue模块提供的类。
import queue
① 普通队列 Queue
先进先出
import queue
q1 = queue.Queue()
q1.put('xxx')
q1.get() # 如果当前队列没有数据 则会堵塞
② 堆栈 LifoQueue
后进先出
import queue
q1 = queue.LifoQueue()
q1.put('xxx')
q1.get() # 如果当前队列没有数据 则会堵塞
③ 优先级 PriorityQueue
import queue
q1 = queue.PriorityQueue()
q1.put((1,'xxx')) # 参数需要为元组,第一个元素表示优先级,数字越小优先级越高,第二个元素表示数据
q1.get() # 如果当前队列没有数据 则会堵塞
3、互斥锁
互斥锁用于控制多个线程之间对共享资源的访问。互斥锁可以确保在任何时刻只有一个线程可以访问共享资源,从而避免了多个线程同时修改共享资源而导致的数据竞争和不一致问题。Python中的互斥锁可以使用threading模块提供的Lock类来实现。在使用互斥锁时,需要首先获取锁,然后访问共享资源,最后释放锁。如果在获取锁时发现锁已经被其他线程占用,则当前线程会被阻塞,直到锁被释放为止。
mutex = threading.Lock() # 创建锁
mutex.acquire() # 上锁
# xxxxxx # 上锁代码
mutex.release() # 释放锁,同一锁被释放前,不能再次上锁
4、进程
指在操作系统中正在运行的代码+所需系统资源实例称之为进程。
Python 通过 multiprocessing 模块来支持多进程编程,可以使用该模块创建、管理和控制多个进程。
① 函数方式创建进程
import multiprocessing # 导入进程包
def p_a(): # 创建函数a
pass
process_1 = multiprocessing.Process(target=p_a,args=(),kwargs={}) # 创建子进程
process_1.start() # 启动子进程
② 类方式创建进程
import multiprocessing # 导入进程包
class Process1(multiprocessing.Process): # 自定义 并继承multiprocessing.Process类
def run(self): # 添加run()方法,start()自动调用该方法
pass
process_1 = Process1()
process_1.start()
import multiprocessing
import time
def p_1():
while 1:
print("i am p_1")
time.sleep(1)
class Process1(multiprocessing.Process):
def run(self):
while 1:
print("i am process_1")
time.sleep(1)
if __name__ == '__main__':
process_1 = Process1()
process_1.start()
p1 = multiprocessing.Process(target=p_1)
p1.start()
while 1:
print("i am main")
time.sleep(1)
③ 进程中的队列
在multiprocessing模块中,队列(Queue)是一种用于在多个进程之间安全地传递数据的数据结构。队列的实现可以使用multiprocessing模块提供的Queue类。与Python中的线程队列类似,multiprocessing中的队列也提供了线程安全的入队和出队操作,可以安全地在多个进程之间共享。需要注意的是,在使用multiprocessing中的队列时,由于不同进程之间的内存空间是相互独立的,因此需要使用特殊的进程锁(Lock)来确保数据的同步和正确性。
import multiprocessing
p_q = multiprocessing.Queue(x) # 创建一个进程队列p_q,最多可以接收x条put
p_q.put("aaa")
p_q.full() # 判断队列是否满,返回True/False
p_q.empty() # 判断队列是为空,返回True/False
p_q.get()
import multiprocessing
p_q = multiprocessing.Queue(4)
print("当前队列是否为空:",p_q.empty()) # 使用p_q.empty()判断队列是否为空
p_q.put("aaa")
print("当前队列是否为空:",p_q.empty())
p_q.put("bbb")
p_q.put("ccc")
p_q.put("ddd")
print("当前队列是否已满:",p_q.full()) # 使用p_q.full()判断队列是否已满
try:
p_q.put("eeeeeee",timeout=2) # 等待两秒后put进入队列,使用try except抛出异常
except:
print("当前队列已满,队列里面有:",p_q.qsize()) # 使用p_q.qsize()查看队列当前数量
try:
p_q.put_nowait("ffff") # 立刻put到当前队列,不等待,无法进入则抛出异常
except:
print("当前队列已满,队列里面有:",p_q.qsize())
④ 进程间通信
案例1:进程间通信有管道、socket、队列等方法,此处演示队列方法
import multiprocessing
import time
def task1(q):
for i in ["aa","bbb","cc","dd","eeeeee"]:
q.put(i)
print(i,'已进入队列')
time.sleep(1)
def task2(q):
while 1:
if not q.empty():
qi = q.get()
print("已从队列取出",qi)
time.sleep(1)
else:
break
if __name__ == '__main__':
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=task1,args=(q,))
p2 = multiprocessing.Process(target=task2, args=(q,))
p1.start()
p2.start()
5、 线程与进程区别
进程跟线程,都可以完成多任务
进程:一台电脑上登录多个QQ
线程:一个QQ中打开多个聊天窗口
① 线程共享全局变量,进程不共享
当一个进程结束时,不会对另一个进程产生影响
import multiprocessing
import time
A=1
def p_1():
global A
A=999
print("p_1结果是:"+str(A))
def p_2():
print("p_2结果是:"+str(A))
if __name__ == '__main__':
p1 = multiprocessing.Process(target=p_1)
p2 = multiprocessing.Process(target=p_2)
p1.start()
time.sleep(2)
p2.start()
此处A=999并没有传入p_2()
② 所有的线程都在同一个进程中
③ 线程开销小,但不利于资源的管理和保护,进程相反
6、进程池
由于进程创建跟关闭的开销大,可以使用进程池来让进程 “重复利用”
# 主进程
import multiprocessing
pool = multiprocessing.Pool(x) # 创建进程池,表示最多有x个进程同时运行
def p(num):
pass
# 往进程池中新增子进程,池满则等待前面进程结束后再往池里新增
for i in range(10):
pool.apply_async(p,(i,))
pool.close() # 关闭进程池
pool.join() # 主进程不会等待子进程结束再结束,需要添加pool.join()等待子进程全部结束后,先回收结束的子进程资源再开始主进程往下运行
① 案例1:
这个案例说明,从进程pid可以看出,进程可以重复利用,不需要重新新建进程与关闭进程
import multiprocessing
import time
import os
def p(num):
print("现在执行的是子进程",num)
print("子进程号是:",os.getpid())
time.sleep(1)
if __name__ == "__main__":
print("主进程号是:",os.getpid())
pool = multiprocessing.Pool(2)
for i in ['AA','BB','CC','DD','EE','ff']:
pool.apply_async(p,(i,))
pool.close()
pool.join()
print("主进程 {} 结束".format(os.getpid()))
② 进程池间通信
使用进程池中的queue
案例1:
import multiprocessing
q = multiprocessing.Manager().Queue() # 使用进程池中的queue
import multiprocessing
import os
import time
def task1(queue):
print("我是子进程1,进程号是:",os.getpid())
for i in ['AA','BB','CC','DD','EE','ff']:
queue.put(i)
print("从队列插入:",i)
time.sleep(2)
def task2(queue):
print("我是子进程2,进程号是:",os.getpid())
while 1:
try:
print("从队列取出:",queue.get(timeout=3))
time.sleep(1)
except multiprocessing.TimeoutError:
print("Queue is empty for 5 seconds, exiting...")
break
if __name__ == "__main__":
print("我是主进程,进程号是:",os.getpid())
pool_queue = multiprocessing.Manager().Queue() # 创建进程池队列
pool = multiprocessing.Pool(2) # 创建进程池
pool.apply_async(task1,(pool_queue,)) # 将task1加入进程池
time.sleep(1)
pool.apply_async(task2,(pool_queue,)) # 将task2加入进程池
pool.close()
pool.join()
print("主进程 {} 结束".format(os.getpid()))