python 进程与线程是并发编程的两种常见方式。进程是操作系统中的一个基本概念,表示程序在操作系统中的一次执行过程,拥有独立的地址空间、资源、优先级等属性。线程是进程中的一条执行路径,可以看做是轻量级的进程,与同一个进程中的其他线程共享相同的地址空间和资源。
线程和进程都可以实现并发编程,但是它们之间有几点不同:
- 线程间共享进程的内存空间,但进程间的内存空间是相互独立的;
- 线程创建和销毁的开销较小,但是线程切换的开销较大;
- 进程间通信需要较为复杂的 IPC(Inter-Process Communication)机制,线程间通信则可以直接读写共享内存;
- 多进程可以充分利用多核 CPU 的性能,但是多线程受 GIL(Global Interpreter Lock)限制,只能利用单核 CPU 的性能。
在选择使用进程还是线程时,需要根据具体场景和需求进行权衡和选择。如果任务需要充分利用多核 CPU,且任务之间互不影响,可以选择多进程;如果任务之间需要共享资源和数据,可以选择多线程。同时,需要注意在 python 中使用多线程时,由于 GIL 的存在,可能无法实现真正的并行。
8.1 创建并使用线程
线程是操作系统调度的最小执行单元,是进程中的一部分,能够提高程序的效率。在python中,创建线程需要使用threading模块。该模块的实现方法是底层调用了C语言的原生函数来实现线程的创建和管理。在系统中,所有的线程看起来都是同时执行的,但实际上是由操作系统进行时间片轮转调度的。
使用函数创建线程: 创建线程并传递参数实现指定函数多线程并发,使用join
方法,等待线程执行完毕后的返回结果.
import os,time
import threading
now = lambda:time.time()
def MyThread(x,y): # 定义每个线程要执行的函数体
time.sleep(5) # 睡眠5秒钟
print("传递的数据:%s,%s"%(x,y)) # 其中有两个参数,我们动态传入
if __name__ == "__main__":
ThreadPool = []
start = now()
for item in range(10): # 创建10个线程并发执行函数
thread = threading.Thread(target=MyThread,args=(item,item+1,)) # args =>函数的参数
thread.start() # 启动线程
ThreadPool.append(thread)
for item in ThreadPool:
item.join()
print("[+] 线程信息: {}".format(item))
stop = now()
print("[+] 线程总耗时: {} s".format(int(stop-start)))
使用类创建内部线程: 通过定义类,将线程函数与类进行结合实现一体化该方式调用方便思维明确.
import os,time
import threading
class MyThread(threading.Thread):
def __init__(self,x,y):
super(MyThread, self).__init__()
self.x = x
self.y = y
def run(self): # 用于执行相应操作(固定写法)
print("[+] 当前执行运算: {} + {}".format(self.x,self.y))
self.result = self.x + self.y
def get_result(self): # 获取计算结果
try:
return self.result
except Exception:
return None
if __name__ == "__main__":
ThreadPool = []
for item in range(1,10):
obj = MyThread(item,item+1)
obj.start()
ThreadPool.append(obj)
for item in ThreadPool:
item.join()
print("[+] 获取返回: ",item.get_result())
使用类创建外部线程: 该定义方式与上方完全不同,我们可以将执行过程定义到类的外部为单独函数,然后类内部去调用传参.
import os,time
import threading
def MyThreadPrint(x,y):
print("[+] 当前执行运算: {} + {}".format(x,y))
result = x + y
return result
class MyThread(threading.Thread):
def __init__(self,func,args=()):
super(MyThread, self).__init__()
self.func = func
self.args = args
def run(self):
self.result = self.func(*self.args)
def get_result(self):
try:
return self.result
except Exception:
return None
if __name__ == "__main__":
ThreadPool = []
for item in range(1,10):
obj = MyThread(func=MyThreadPrint,args=(item,item+1))
obj.start()
ThreadPool.append(obj)
for item in ThreadPool:
item.join()
print("[+] 获取返回: ",item.get_result())
在线程中创建子线程: 通过创建一个守护线程,并让守护线程调用子线程,从而实现线程中调用线程,线程嵌套调用.
import time
import threading
# run => 子线程 => 由主线程调用它
def run(num):
print("这是第 {} 个子线程".format(num))
time.sleep(2)
# main = > 主守护线程 => 在里面运行5个子线程
def main():
for each in range(5):
thread = threading.Thread(target=run,args=(each,))
thread.start()
print("启动子线程: {} 编号: {}".format(thread.getName(),each))
thread.join()
if __name__ == "__main__":
daemon = threading.Thread(target=main,args=())
daemon.setDaemon(True) # 设置主线程为守护线程
daemon.start() # 启动守护线程
daemon.join(time