进程:执行中的程序。包括代码段、程序计数器、堆栈段(临时数据,如局部变量、函数参数和返回地址)、堆(进程运行期间动态分配的内存)、进程状态、CPU 调度信息、I/O状态信息(如打开文件列表)
(详见《操作系统概念(第 7 版)》 - P73)
线程是 CPU 使用的基本单元,由线程 ID、程序计数器、寄存器集合和栈组成。
线程与属于同一进程的其他线程共享代码段、公共数据段、打开文件和信号等等。
区别 1:和线程不同,进程没有任何共享状态;如果某个进程修改数据,改动只限于那个进程内。
(Python 参考手册 - P336)
区别 2:Python 中的多进程可以实现真正的并行,Python 中的多线程不能实现真正的并行。
(OS概念 - 第 7 版 - P112)
线程优点:
由于 GIL 的存在,这个锁保证同一时刻只有 1 个线程在运行。
(《Python 核心编程(第 2 版)》 - 18.3.1 全局解释器锁 ( GIL ) - P514)
即使是多核 CPU,使用多线程编程,各个线程也只能交替使用 CPU 。
因此Python 中的多线程并不能实现真正的并行。
(Python 3 教程 - 廖雪峰 - 进程和线程 - 多线程 - 多核 CPU 。)
如果 1 个进程是后台进程,那么,当创建这个后台进程的进程终止,后台进程会自动终止。
(Python 参考手册 - P337)
代码清单 - 1
# p337_single_process_with_function.py
from multiprocessing import Process
from time import ctime, sleep
def clock(interval):
while True:
print("The time is %s" % ctime())
sleep(interval)
if __name__ == "__main__":
p = Process(target=clock, args=(2,))
#p.daemon = False
p.start()
#print("hello!")
#p.join()
代码清单 - 2
# p337_single_process_with_function_Daemon_False.py
from multiprocessing import Process
from time import ctime, sleep
def clock(interval):
while True:
print("The time is %s" % ctime())
sleep(interval)
if __name__ == "__main__":
p = Process(target=clock, args=(2,))
p.daemon = False
p.start()
#print("hello!")
#p.join()
以上两段代码均会永远执行。
补充一点背景知识:
上面的两段代码的区别仅仅在于是否显式地将进程 p 设置为非后台进程,第 1 段代码虽然未将子进程 p 设置为非后台进程,但是,实际上效果等于第 2 段代码中 p.daemon = False
,将子进程 p 的 daemon 标志设置为 False。
实际上可以认为两段代码是一样的。
下面仅解释第 2 段代码:
p = Process(target=clock, args=(2,))
创建 1 个子进程 p,
p.daemon = False 将子进程 p 的daemon 标识设置为 False,
p.start() 以子进程 p 启动函数,
代码继续往下执行,主进程结束;由于子进程不是后台进程,因此,子进程 p 不会随主进程结束而结束,子进程 p 会继续运行,由于子进程 p 中的函数 clock 是死循环,因此子进程 p 会永远运行。
如下代码将子进程 p 的daemon 标志设置为 True:
代码清单 - 3
from multiprocessing import Process
from time import ctime, sleep
def clock(interval):
while True:
print("The time is %s" % ctime())
sleep(interval)
if __name__ == "__main__":
p = Process(target=clock, args=(2,))
p.daemon = True
p.start()
#print("hello!")
#p.join()
解释:
p.daemon = True
将子进程 p 设置为后台进程,因此,如果主进程结束,子进程 p (后台进程)也会随之结束;
p.start()
子进程 p 启动,执行clock函数;
代码继续往下执行,主进程结束,子进程 p 也随之结束(即使 clock 函数内部是死循环)。
参考文献:
Python 参考手册 - P337;
https://github.com/henry199101/python_CanKao_ShouCe/blob/master/chapter_20/p337_single_process_with_function.py;
https://github.com/henry199101/python_CanKao_ShouCe/blob/master/chapter_20/p337_single_process_with_function_Daemon_False.py;
https://github.com/henry199101/python_CanKao_ShouCe/blob/master/chapter_20/p337_single_process_with_function_Daemon_True.py
代码清单 - 4
from multiprocessing import Process
from time import ctime, sleep
class ClockProcess(Process):
def __init__(self, interval):
Process.__init__(self)
self.interval = interval
def run(self):
while True:
print("The time is %s" % ctime())
sleep(self.interval)
if __name__ == "__main__":
p = ClockProcess(2)
p.start()
代码清单 4 中,进程 p 是非后台进程,与代码清单1、2相同,不再做详细解释。
参考文献:
Python 参考手册 - P337
https://github.com/henry199101/python_CanKao_ShouCe/blob/master/chapter_20/p337_single_process_with_class.py。
进程间通信方式:管道、命名管道、消息队列、套接字、信号量、信号、共享内存、内存映射。
(https://blog.csdn.net/qq_33528613/article/details/77187572)
(unix进程间通信方式(IPC))
multiprocessing 模块支持的进程间通信的 2 种主要形式:队列和管道。
(Python 参考手册 - P337)
from multiprocessing import Process, Queue
def consumer(q):
while True:
item = q.get()
if item is None:
break
print(item)
def producer(sequence, q):
for item in sequence:
q.put(item)
if __name__ == "__main__":
q = Queue()
consumer_process = Process(target=consumer, args=(q,))
consumer_process.start()
sequence = [1, 2, 3, 4]
producer(sequence, q)
q.put(None)
consumer_process.join()
(https://github.com/henry199101/python_CanKao_ShouCe/blob/master/chapter_20/p340_producer_consumer_shao_bing.py)
(Python 参考手册 - P340)
暂时略
(https://github.com/henry199101/python_CanKao_ShouCe/blob/master/chapter_20/p339_producer_consumer_JoinableQueue.py)
(Python 参考手册 - P339)
from multiprocessing import Process, Pipe
def consumer(pipe):
output_side, input_side = pipe
input_side.close()
while True:
try:
item = output_side.recv()
except EOFError:
break
print(item)
output_side.close()
def producer(sequence, pipe):
output_side, input_side = pipe
output_side.close()
for item in sequence:
input_side.send(item)
input_side.close()
if __name__ == "__main__":
pipe = Pipe()
consumer_process = Process(target=consumer, args=(pipe,))
consumer_process.start()
sequence = [1,2,3,4]
producer(sequence, pipe)
consumer_process.join()
解释:
from multiprocessing import Process, Pipe
def adder(pipe):
server_side, client_side = pipe
client_side.close()
while True:
try:
x, y = server_side.recv()
except EOFError:
break
result = x + y
server_side.send(result)
print("Done!")
if __name__ == '__main__':
pipe = Pipe()
server_side, client_side = pipe
adder_process = Process(target=adder, args=(pipe,))
adder_process.start()
server_side.close()
client_side.send((3, 4))
print(client_side.recv())
client_side.send(('Hello, ', 'World!'))
print(client_side.recv())
client_side.close()
adder_process.join()
(Python 参考手册 - P342——P343)
解释:
不做详细解释,请看图示,一目了然。
# 程序来自廖雪峰Python
#https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431927781401bb47ccf187b24c3b955157bb12c5882d000#0
from multiprocessing import Pool
from time import time, sleep
from os import getpid
from random import random
def long_time_task(name):
print("Task %s (%s) starts..." % (name, getpid()))
start = time()
sleep(random() * 3)
end = time()
elapsed_time = end - start
print("Task %s runs %.2f seconds!" % (name, elapsed_time))
if __name__ == "__main__":
print("Main process (%s) starts..." % getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print("Waiting for all subprocesses done!")
p.close()
p.join()
print("All subprocesses done!")
输出:
$ python3 p343_p345_process_pool.py
Main process (2701) starts...
Waiting for all subprocesses done!
Task 0 (2702) starts...
Task 1 (2703) starts...
Task 3 (2704) starts...
Task 2 (2705) starts...
Task 2 runs 0.23 seconds!
Task 4 (2705) starts...
Task 3 runs 0.32 seconds!
Task 0 runs 0.64 seconds!
Task 1 runs 1.49 seconds!
Task 4 runs 1.75 seconds!
All subprocesses done!
解释:
p.apply_async() 在 1 个池进程中,异步地执行函数;
p.close() 用于关闭进程池;
p.join() 等待所有工作进程退出。
进程池开启了 4 个子进程,但却有 5 个子任务,因此最后 1 个子任务需要等到前面的 4 个进程中执行完 1 个,才能开始执行。
参考文献:
廖雪峰 - Python 3 - 多进程 - Pool
Python 参考手册 - P343——P345
(Python 参考手册 - P352——P353)
服务器:
from multiprocessing.connection import Listener
server = Listener(address=('', 15000), authkey='12345')
while True:
conn = server.accept()
while True:
try:
x, y = conn.recv()
except EOFError:
break
result = x + y
conn.send(result)
conn.close()
客户端:
from multiprocessing.connection import Client
conn = Client(address=('localhost', 15000), authkey='12345')
conn.send((2, 3))
result = conn.recv()
print(result)
conn.send(('Hello, ', 'World!'))
result = conn.recv()
print(result)
conn.close()
from threading import Thread
from time import ctime, sleep
def clock(interval):
while True:
print("The time is %s" % ctime())
sleep(interval)
t = Thread(target=clock, args=(2,))
t.daemon = True
t.start()
from threading import Thread
from time import sleep, ctime
class ClockThread(Thread):
def __init__(self, seconds):
Thread.__init__(self)
self.seconds = seconds
self.daemon = False
def run(self):
while True:
print('The time is %s' % ctime())
sleep(self.seconds)
if __name__ == '__main__':
t = ClockThread(2)
t.start()
(Python 核心编程)
可能暂时略