Process 类
创建进程:
1. p = Process(target=callable,name='',args='',kwargs='')
2. p.start() 启动进程
一、
主进程:执行的时候,默认的进程称作主进程
子进程:在主进程中可以开启子进程
p1 = Process(target=callable,args='')
os.getpid() 当前进程
os.getppid() 父进程
二、全局变量
如果是全局变量则,每个进程都会拥有一份全局变量。各自操作各自的全局变量
三、阻塞主进程
子进程.join()
阻塞主进程后面的代码
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)
进程对象可以访问方法:
run()
start()
join()
terminate()
close() target完成之后调用的close()释放资源
is_alive() 判断target任务是否完成,如果任务完成则False,没有完成True (是否是活动的)
def task1():
for i in range(5):
print('洗衣服:', i, os.getpid(), os.getppid())
time.sleep(0.5)
def task2(n):
for i in range(n):
print('劳动最光荣,扫地中...', i, os.getpid(), os.getppid())
time.sleep(0.5)
# print('number:', 100)
if __name__ == '__main__':
p1 = Process(target=task1)
p2 = Process(target=task2, args=(6,))
# p1.run()
# p2.run()
p1.start()
p2.start()
for i in range(10):
if i == 4:
p1.terminate() # 终止p1进程
elif i == 5:
p2.terminate()
time.sleep(0.3)
print('main:', i)
p2.close()
print("p1是否活着:", p1.is_alive())
print("p2是否活着:", p2.is_alive())
**进程池:**
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')
**阻塞式**
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')
进程间通信与信号量
队列:
FIFO
put() : 队列中存放,如果满了则阻塞
get() : 从队列中取值,如果空了则阻塞
full() 判断是否是满了
empty() 判断是否是空了 如果空了,True
qsize() 获取长度
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
用process实现分进程网上下载图片:
p = Process(target=func(函数名),name='',args=(参数),kwargs={})
def download(urls, queue): # urls = images
for image_url in urls:
response = requests.get(image_url)
image_data = response.content
queue.put(image_data)
def save_file(queue):
count = 0
while True:
try:
data = queue.get(timeout=5)
# 保存到本地
filename = 'img' + str(count) + '.jpg'
with open('images/' + filename, 'wb') as ws:
ws.write(data)
count += 1
print('保存{}完毕!'.format(filename))
except Exception as err:
print('没有更多数据啦!')
break
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'
]
p1 = Process(target=download, args=(images, q1))
p2 = Process(target=save_file, args=(q1,))
start = time.time() # 开始的时间戳
p1.start()
p2.start()
p1.join()
p2.join()
end = time.time() # 结束的时间戳
print('用时:{}秒'.format(end - start))
用重写run方法实现下载图片:
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_xI4khGkpoWK1HF6h
hy/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)
**python 如何创建一个线程?**
**线程:**
1. t1 = Thread(target=task1)
2. 自定义线程
run()
start()#开始
join()#阻塞 把前面的线程运行完之后在运行
name: 默认的Thread-1, Thread-2,....
current_thread().name 获取当前线程的名字
is_alive#判断是否线程还活着
'''
python 如何创建一个线程?
线程:
1. t1 = Thread(target=task1)
2. 自定义线程
run()
start()
join()
name: 默认的Thread-1, Thread-2,....
current_thread().name 获取当前线程的名字
is_alive
'''
import os
import time
from threading import Thread,current_thread
def task1():
for i in range(5):
print('{}洗衣服:'.format(current_thread().name), i, os.getpid(), os.getppid())
time.sleep(0.5)
def task2(n):
for i in range(n):
print('{}劳动最光荣,扫地中...'.format(current_thread().name), i, os.getpid(), os.getppid())
time.sleep(0.5)
if __name__ == '__main__':
print('main:', os.getpid())
# 创建线程对象
t1 = Thread(target=task1,name='警察')
t2 = Thread(target=task2,name='小偷', args=(6,))
# 启动线程
t1.start()
t2.start()
# t1.join()
# t2.join()
for i in range(3):
print("t1:", t1.is_alive())
print("t2:", t2.is_alive())
print('main:', i)
time.sleep(1)
**自定义线程:**
1. 定义一个类继承Thread
2. 重写: [__init__] 必须重写: run()
3. 创建线程类对象
4. 启动线程
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:
ticket = 10
def sale_ticket():
global ticket
while True:
if ticket > 0:
print('{}正在卖第{}张火车票!'.format(current_thread().name, ticket))
ticket -= 1
time.sleep(1)
else:
break
if __name__ == '__main__':
t1 = Thread(target=sale_ticket, name='1号窗口')
t2 = Thread(target=sale_ticket, name='2号窗口')
t3 = Thread(target=sale_ticket, name='3号窗口')
t1.start()
t2.start()
t3.start()
因为有锁的形式所以当时间大,运算量大的时候会出现不准的轻快,所以有锁的形式:
from threading import Thread, Lock
number = 0
def task(lock):
global number
lock.acquire() # 握住
for i in range(100000):
number += 1
lock.release() # 释放锁
if __name__ == '__main__':
lock = Lock()
t1 = Thread(target=task, name='1号窗口', args=(lock,))
t2 = Thread(target=task, name='2号窗口', args=(lock,))
t3 = Thread(target=task, name='3号窗口', args=(lock,))
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print('number:', number)
**锁:**
from threading import Lock
lock = Lock()
lock.acquire()
lock.release()