进程
单进程
import time
def cook():
for i in range(3):
print("做饭...")
time.sleep(0.5)
def wash():
for i in range(3):
print("洗衣服...")
time.sleep(0.5)
if __name__ == '__main__':
cook()
wash()
运行结果
做饭...
做饭...
做饭...
洗衣服...
洗衣服...
洗衣服...
可使用多进程方式让两个任务同步执行
多进程
from time import sleep
from multiprocessing import Process
def cook():
for i in range(3):
print("做饭...")
sleep(0.5)
def wash():
for i in range(3):
print("洗衣服...")
sleep(0.5)
if __name__ == '__main__':
# 使用进程类创建进程对象
cook_process = Process(target=cook)
wash_process = Process(target=wash)
# 使用进程对象启动进程执行指定任务
cook_process.start()
wash_process.start()
运行结果
做饭...
洗衣服...
做饭...
洗衣服...
做饭...
洗衣服...
带参数
-
args
以元组形式给进程传递参数 -
kwargs
以字典形式给进程传递参数
from time import sleep
from multiprocessing import Process
def cook(num):
for i in range(num):
print("做饭...")
sleep(0.5)
def wash(num):
for i in range(num):
print("洗衣服...")
sleep(0.5)
if __name__ == '__main__':
# 使用进程类创建进程对象
cook_process = Process(target=cook, args=(2, ))
wash_process = Process(target=wash, args=(5, ))
# cook_process = Process(target=cook, kwargs={"num": 2})
# wash_process = Process(target=wash, kwargs={"num": 2})
# 使用进程对象启动进程执行指定任务
cook_process.start()
wash_process.start()
运行结果
做饭...
洗衣服...
做饭...
洗衣服...
洗衣服...
洗衣服...
洗衣服...
进程信息
- 获取当前进程编号
import os
pid = os.getpid()
print(pid)
- 获取当前进程父进程编号
import os
from time import sleep
from multiprocessing import Process
def cook():
print("做饭进程""pid: ", os.getpid())
sleep(0.5)
print("做饭进程父进程pid: ", os.getppid())
def wash():
print("洗衣服进程pid: ", os.getpid())
sleep(0.5)
print("洗衣服进程父进程pid: ", os.getppid())
if __name__ == '__main__':
print("主进程pid: ", os.getpid())
cook_process = Process(target=cook)
wash_process = Process(target=wash)
cook_process.start()
wash_process.start()
运行结果
主进程pid: 17144
做饭进程pid: 16528
洗衣服进程pid: 16520
做饭进程父进程pid: 17144
洗衣服进程父进程pid: 17144
守护进程
主进程会等待所有子进程执行结束再结束, 实际开发过程中则希望主进程结束时结束所有子进程, 此时主进程需创建守护进程
守护进程特点,
-
守护进程会在主进程代码执行结束后就终止
-
守护进程内无法再开启子进程, 否则抛出异常
AssertionError: daemonic processes are not allowed to have children
- 进程之间是互相独立的, 主进程代码运行结束, 守护进程随即终止
import os
from time import sleep
from multiprocessing import Process
def work():
for i in range(10):
print("Work in [{0}]".format(i))
sleep(0.5)
if __name__ == '__main__':
# 创建子进程
work_process = Process(target=work)
# 设置守护进程, 主进程结束后子进程直接销毁
work_process.daemon = True
work_process.start()
sleep(2)
print("主进程结束!")
运行结果
Work in [0]
Work in [1]
Work in [2]
Work in [3]
主进程结束!
主进程结束时子进程也立即结束
线程
定义
进程是由若干线程组成, 一个进程至少有一个线程
线程是操作系统直接支持的执行单元
python线程是真正Posix Thread, 而不是模拟线程
from time import sleep
from threading import Thread, current_thread
def loop():
name = current_thread().name
for i in range(5):
print('子线程 [{0}_{1}]运行'.format(name, i))
sleep(0.5)
if __name__ == "__main__":
name = current_thread().name
print('线程 [{0}] 运行...'.format(name))
# 子线程命名LoopThread, 否则Python自动命名为Thread-1, Thread-2..., 名字无意义, 仅仅在打印时显示
t = Thread(target=loop, name='LoopThread')
t.start()
t.join()
print("线程 [{0}] 结束".format(name))
任何进程默认就会启动一个主线程, 主线程又可以启动新线程
threading模块current_thread()函数, 永远返回当前线程实例
主线程实例名叫MainThread
互斥锁
多进程中, 同一个变量各有一份拷贝存在于每个进程中, 互不影响
多线程中, 所有变量都由所有线程共享, 任何变量都可以被任何一个线程修改
因此线程之间共享数据最大危险在于多个线程同时改一个变量, 造成内容混乱
- 使用
import threading
lock = threading.Lock()
# 获取锁
lock.acquire()
# 释放锁
lock.release()
上下文管理
import threading
lock = threading.Lock()
with lock:
pass
with
语句会在执行前自动获取锁, 执行结束后自动释放
例如银行存款时, 多线程操作时, 每一次存钱与取钱前都需要加锁, 避免余额错误
from threading import Thread, Lock
g_balance = 0
lock = Lock()
def change_it(n):
# 先存后取, 结果应该为0
global g_balance
g_balance += n
g_balance -= n
def run_thread(n):
global lock
for i in range(1000):
with lock:
change_it(i)
if __name__ == '__main__':
lock = Lock()
t1 = Thread(target=run_thread, args=(5, ))
t2 = Thread(target=run_thread, args=(8, ))
threads = [
Thread(target=run_thread, args=(5, )),
Thread(target=run_thread, args=(8, ))
]
for i in threads:
i.start()
for i in threads:
i.join()
print(g_balance)