一、进程
Python进程是操作系统中执行的独立的任务实体,每个进程都有自己的地址空间和系统资源(进程之间相互隔离,不能共享进程变量)。Python的多进程模块multiprocessing
可以用来创建和管理进程。每个进程都可以独立执行,拥有自己的全局变量和代码执行流程。进程之间通过进程间通信(IPC)来进行数据交换。
常用方法
1.创建进程:可以使用Process
类来创建进程。首先导入multiprocessing
模块,然后通过Process
类的构造函数创建一个进程对象。
from multiprocessing import Process
def func():
print("Hello, World!")
if __name__ == "__main__":
p = Process(target=func)
p.start()
p.join()
上面的例子使用了target关键字指定了进程对应的函数,在 Process
类中,除了 target
参数,还有一些其他可用的参数可以用来控制子进程的行为。以下是一些常用的参数:
args
:一个元组,用于传递给target
函数的位置参数。kwargs
:一个字典,用于传递给target
函数的关键字参数。name
:一个字符串,用于设置子进程的名称。daemon
:一个布尔值,用于设置子进程是否为守护进程。group
:一个Group
对象,用于将子进程添加到指定的进程组。
2.进程间通信:不同进程之间无法直接共享内存,需要使用特定的机制进行进程间通信。multiprocessing
模块提供了Queue
、Pipe
等用于进程间通信的类。例如,使用Queue
实现进程间的消息传递:
from multiprocessing import Process, Queue
def func(q):
q.put("Hello, World!")
if __name__ == "__main__":
q = Queue()
p = Process(target=func, args=(q,))
p.start()
print(q.get())
p.join()
3.进程池:如果需要同时执行多个进程,可以使用进程池来管理进程。multiprocessing
模块提供了Pool
类来实现进程池。例如,使用进程池并行执行多个任务:
from multiprocessing import Pool
def func(x):
return x * x
if __name__ == "__main__":
with Pool(processes=4) as pool:
result = pool.map(func, range(10))
print(result)
4.共享内存:虽然不同进程之间无法直接共享内存,但可以使用Value
和Array
等类来创建共享内存。例如,使用Value
创建一个共享的整数:
from multiprocessing import Process, Value
def func(n):
n.value += 1
if __name__ == "__main__":
n = Value('i', 0)
p1 = Process(target=func, args=(n,))
p2 = Process(target=func, args=(n,))
p1.start()
p2.start()
p1.join()
p2.join()
print(n.value)
进程特点
-
独立性:每个进程都是一个独立的实体,有自己独立的内存空间和系统资源。进程之间相互隔离,一个进程的错误不会影响其他进程的运行。
-
并发性:多个进程可以同时执行,每个进程都有自己的执行流。操作系统通过时间片轮转等调度算法来切换进程的执行,使得进程看起来是同时运行的。
-
隔离性:不同进程之间的内存空间是隔离的,一个进程无法直接访问另一个进程的内存。进程之间的通信需要通过特定的机制,如管道、消息队列等。
-
共享性:虽然进程之间的内存是隔离的,但可以通过特定的机制实现进程间的数据共享。例如,使用共享内存、文件等来实现进程间的数据交换。
-
系统开销:每个进程都需要占用一定的系统资源,如内存、CPU时间等。创建和销毁进程都需要一定的开销,因此过多的进程会增加系统的负担。
-
安全性:由于进程之间的隔离性,进程之间的数据不会相互干扰。这提高了系统的安全性,一个进程的错误不会对其他进程造成影响。
二、线程
Python线程是Python中用于实现并发编程的一种机制。线程是进程内的执行单元,一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文件描述符等。与进程相比,线程的创建和切换开销较小,可以更加高效地实现并发操作。
创建线程:可以通过继承threading.Thread
类或使用threading.Thread
类的构造函数来创建线程。例如:
import threading
# 继承Thread类创建线程
class MyThread(threading.Thread):
def run(self):
# 线程执行的代码
print("Hello, I'm a thread!")
# 使用Thread类的构造函数创建线程
thread = threading.Thread(target=func)
启动线程:通过调用线程对象的start()
方法来启动线程。启动线程后,线程会自动调用run()
方法来执行线程的代码。
thread.start()
线程同步:由于多个线程共享进程的资源,可能会导致资源竞争和数据不一致的问题。可以使用锁(Lock
)来保证线程间的同步。例如:
import threading
# 创建锁对象
lock = threading.Lock()
# 在需要同步的代码块中使用锁
lock.acquire()
# 临界区代码
lock.release()
线程间通信:线程间可以通过共享变量来进行通信。为了避免数据竞争,可以使用Queue
等线程安全的数据结构来实现线程间的数据传递。
import threading
from queue import Queue
# 创建队列对象
queue = Queue()
# 在生产者线程中向队列中放入数据
queue.put(data)
# 在消费者线程中从队列中取出数据
data = queue.get()
线程状态:线程可以处于就绪、运行、阻塞等不同的状态。可以通过threading.Thread
类的is_alive()
方法来判断线程是否在运行。
thread.is_alive() # 判断线程是否在运行
三、协程
协程是一种用户级线程,也被称为轻量级线程。协程在同一个线程中执行,共享同一个地址空间和系统资源。协程可以在执行过程中主动让出CPU,并保存当前执行的上下文,以便后续重新恢复执行。Python的协程模块asyncio
提供了一种基于事件循环的协程编程模型。协程之间通过await
和async
关键字来进行协作和数据交换。
在Python中,可以使用threading
模块来创建和管理线程。下面是一些常用的线程操作:
1、创建线程:可以通过继承threading.Thread
类或使用threading.Thread
类的构造函数来创建线程。例如:
import threading
# 继承Thread类创建线程
class MyThread(threading.Thread):
def run(self):
# 线程执行的代码
print("Hello, I'm a thread!")
# 使用Thread类的构造函数创建线程
thread = threading.Thread(target=func)
2、启动线程:通过调用线程对象的start()
方法来启动线程。启动线程后,线程会自动调用run()
方法来执行线程的代码。
thread.start()
3、线程同步:由于多个线程共享进程的资源,可能会导致资源竞争和数据不一致的问题。可以使用锁(Lock
)来保证线程间的同步。例如:
import threading
# 创建锁对象
lock = threading.Lock()
# 在需要同步的代码块中使用锁
lock.acquire()
# 临界区代码
lock.release()
4、线程间通信:线程间可以通过共享变量来进行通信。为了避免数据竞争,可以使用Queue
等线程安全的数据结构来实现线程间的数据传递。
import threading
from queue import Queue
# 创建队列对象
queue = Queue()
# 在生产者线程中向队列中放入数据
queue.put(data)
# 在消费者线程中从队列中取出数据
data = queue.get()
5、线程状态:线程可以处于就绪、运行、阻塞等不同的状态。可以通过threading.Thread
类的is_alive()
方法来判断线程是否在运行。
thread.is_alive() # 判断线程是否在运行
四、异步编程
异步编程是一种编程模式,用于处理并发和并行的任务。在传统的同步编程中,代码按照顺序依次执行,每个操作都会阻塞代码的执行,直到操作完成才能继续执行下一个操作。而在异步编程中,代码可以在等待某个操作完成的同时继续执行其他操作,从而提高程序的并发性和响应能力。
异步编程的核心概念是协程(coroutine)和事件循环(event loop)。(涉及到asyncio 库,我也不太懂)
协程
协程是一种特殊的函数,它可以在执行过程中暂停并保存当前的状态,然后可以在需要的时候恢复执行。在Python中,协程是通过生成器实现的。然而协程与生成器的概念并不相同,协程消费数据,生成器生成数据 ,同时协程与迭代无关。
我们可以使用async和await关键字来定义和管理协程 ,async作为协程关键字,放在协程函数前,await关键字用于暂停协程执行,等待一个异步操作的结果。
示例:
import asyncio
async def my_coroutine():
print("协程开始")
await asyncio.sleep(1)
print("协程结束")
上述代码中使用了async关键字生成了一个名为my_coroutine的协程函数,它会打印出“协程开始”然后通过 await asyncio.sleep(1)暂停协程1秒钟,最后打印出“协程结束”。
事件循环
事件循环是异步编程的核心机制,它负责调度和执行协程。事件循环会不断地从任务队列中取出协程,执行一段时间,然后再切换到其他的协程。与GUI不同的是asyncio库写出的事件队列需要手动维护。
事件循环的工作流程如下:(目前我不会用所以给不出例子)
-
创建事件循环对象:使用
asyncio.get_event_loop()
函数获取默认的事件循环对象,或者使用asyncio.new_event_loop()
函数创建一个新的事件循环对象。 -
将协程添加到事件循环中:使用
loop.run_until_complete()
方法将一个协程添加到事件循环中,使其开始执行。事件循环会一直执行,直到协程完成。 -
执行协程:事件循环会不断地从任务队列中取出协程,并执行一段时间。当协程需要等待某个操作完成时,事件循环会将控制权交还给操作系统,然后继续执行其他的协程。
-
等待操作完成:当协程需要等待某个操作完成时,可以使用
await
关键字将控制权交还给事件循环。事件循环会等待操作完成,并在操作完成后再次调度该协程继续执行。 -
停止事件循环:可以使用
loop.stop()
方法停止事件循环的执行。也可以使用loop.run_forever()
方法使事件循环一直执行,直到调用loop.stop()
方法停止。