进程
Process类
进程:一个运行的程序或代码就是一个进程,一个没有运行的代码叫程序。进程是系统进行资源分配的最小单位,进程拥有自己的内存空间,所以进程间数据不共享,开销大。
多进程适合在CPU 密集型操作(cpu 操作指令比较多,如科学计算,位数多的浮点运算) 多线程适合在IO
密集型操作(读写数据操作较多的,比如爬虫)
线程是并发,进程是并行;进程之间相互独立,是系统分配资源的最小单位,同一个进程中的所有线程共享资源。
-
创建进程
- p = Process(target=callble,name=" “,args=’’,keargs=” ")
- p.start()
os.getpid() 获得当前进程号
os.getppid() 获得父线程进程号
-
进程
- 主进程:执行时的默认进程
- 子进程: 全局变量:
- 如果是全局变量,每个进程都会拥有各自的全局变量,互不影响 阻塞主线程
- 子进程对象.join() 方法
-
start()
-
run()
-
terminate()
-
close() target完成后调用close()释放资源
-
is_alive() 任务完成则是False,否则True
import time
import os
from multiprocessing import Process
# print('----->top:', os.getpid())
def task1():
global number
for i in range(5):
print('洗衣服:', i, os.getpid(), os.getppid())
time.sleep(0.5)
number -= 10
print('洗衣服:', number)
def task2(n):
global number
for i in range(n):
print('劳动最光荣,扫地中...', i, os.getpid(), os.getppid())
time.sleep(0.5)
number -= 8
print('扫地:', number)
number = 100
if __name__ == '__main__':
print('main:--->start', os.getpid())
p1 = Process(target=task1)
p2 = Process(target=task2, args=(6,))
p1.start()
p2.start()
# join() 加入 阻塞主进程后面的代码不执行
p1.join()
p2.join()
print('main:--->end', os.getpid())
print('main中的number是:', number)
进程池
Pool
阻塞式
apply
import os
import time
from multiprocessing import Pool
def task1():
for i in range(5):
print('洗衣服:',i, os.getpid(), os.getppid())
time.sleep(0.5)
# return '我是进程:' + str(os.getpid())
if __name__ == '__main__':
pool = Pool(4)
#
for i in range(10):
pool.apply(task1) # 阻塞式: 进程池中一个任务完成之后才能做下一个任务
print('------------------------->',i)
# 添加任务结束
pool.close()
# 阻塞主进程
pool.join()
print('main over')
非阻塞式
apply_async
import os
import time
from multiprocessing import Pool
def task1():
print('洗衣服:', os.getpid(), os.getppid())
time.sleep(0.5)
return '我是进程:' + str(os.getpid())
# response = requests.get(url)
# return response.content
def callback(msg):
print('{}洗衣服任务完成!'.format(msg))
# 保存下载的文件到本地
if __name__ == '__main__':
pool = Pool(4)
# 非阻塞式
for i in range(10):
pool.apply_async(task1, callback=callback)
# 添加任务结束
pool.close()
# 阻塞主进程
pool.join()
print('main over')
进程间的通信
Queue
put() 入队
get() 出队
full() 判断是否为满,满了则返回True
empty() 判断是否为空,若为空则返回True
qsize() 获取长度
'''
进程间通信与信号量
队列:
FIFO
put() : 队列中存放,如果满了则阻塞
get() : 从队列中取值,如果空了则阻塞
'''
from multiprocessing import Process, Queue
queue = Queue(3)
queue.put('馒头1')
queue.put('馒头2')
queue.put('馒头3')
print(queue.full()) # 判断是否满了
print(queue)
print(queue.qsize())
try:
queue.put('馒头4', timeout=3)
queue.put('馒头5', timeout=3)
except:
print('存放馒头失败')
while True:
try:
print(queue.get(timeout=1))
except:
print('队列为空,取不出东西')
break
def download(url, queue):
pass
def save_file(queue):
pass
if __name__ == '__main__':
q1 = Queue(2)
p1 = Process(target=download, args=(url, q1))
p2 = Process(target=save_file, args=(q1,))
p1.start()
p2.start()
p1.join()
p2.join()
自定义进程
'''
p = Process(target=func,name='',args=(),kwargs={})
自定义进程
'''
import os
import time
import requests
from multiprocessing import Process, Queue
class DownloadProcess(Process):
def __init__(self, urls, queue):
Process.__init__(self)
self.urls = urls
self.queue = queue
# 重写父类的run方法
def run(self):
for image_url in self.urls:
filename = os.path.split(image_url)[1]
response = requests.get(image_url)
image_data = response.content
self.queue.put(image_data)
self.queue.get()
print('下载{}完毕'.format(filename))
self.queue.close()
if __name__ == '__main__':
q1 = Queue(2)
images = [
'https://gss0.bdstatic.com/94o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=7bf3ea52d40735fa85fd46ebff3864d6/8644ebf81a4c510f0912aa536059252dd52aa5a1.jpg',
'https://gss1.bdstatic.com/9vo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike92%2C5%2C5%2C92%2C30/sign=aa62e3280fb30f242197e451a9fcba26/eaf81a4c510fd9f906c11d20252dd42a2934a4a1.jpg'
]
dlprocess = DownloadProcess(images, q1)
dlprocess.start()
for i in range(5):
if dlprocess.is_alive():
print('进程是活跃的:', i)
else:
print('进程结束了')
dlprocess.close()
break
time.sleep(0.5)
线程
线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程的存在而存在,一个进程至少有一个线程,叫主线程,多个线程共享内存(数据共享和全局变量),因此提升程序的运行效率。
创建线程
t1 = Thread(target=函数,name=线程名)
自定义线程
import time
from threading import Thread
class MyThread(Thread):
def __init__(self, name):
Thread.__init__(self)
self.name = name
def run(self):
for i in range(5):
print('{}正在打印:{}'.format(self.name, i))
time.sleep(0.1)
if __name__ == '__main__':
t1 = MyThread('小明')
t2 = MyThread('小花')
t3 = MyThread('ergou')
t1.start()
t2.start()
t3.start()
GIL全局变量锁
GIL是什么呢?仍然用篮球比赛的例子来帮助理解:把篮球场看作是CPU,一场篮球比赛看作是一个线程,
如果只有一个篮球场,多场比赛要排队进行,就是一个简单的单核多线程的程序;如果有多块篮球场,
多场比赛同时进行,就是一个简单的多核多线程的程序。然而python有着特别的规定:
每场比赛必须要在裁判的监督之下才允许进行,而裁判只有一个。这样不管你有几块篮球场,
同一时间只允许有一个场地进行比赛,其它场地都将被闲置,其它比赛都只能等待。