进程锁和进程池

进程锁

# 当数据发生变化时,当采用的时多进程存在时间差,就会造成数据紊乱。
# 比如买票,假如这个时候只有一张票,但是所有人都能买,最后打印发现好几个人买到票了,
# 几个人没买到票。
# 因为在一个进程买票后,去修改票数时,由于时间太快,没来得及修改,就回到是其他进程买到票。
# 所以,这个时候就需要进程锁,
# 好比一个上锁的房间,门口只有一个钥匙,一个线程拿到钥匙进去修改数据没出来前,其他进程只能等着

import json
import multiprocessing


def show(i):
    with open('ticket') as f:
        dic = json.load(f)
    print('余票:%s'%dic['ticket'])

def buy_ticket(i, lock):  # 接收锁
    lock.acquire()  # 拿钥匙进门
    with open('ticket') as f:
        dic = json.load(f)
        time.sleep(0.1)
    if dic['ticket'] > 0:
        dic['ticket'] -= 1
        print('%s号买到票了'%i)
    else:
        print('%s号没买到票'%i)
        time.sleep(0.1)
    with open('ticket', 'w') as f:
        json.dump(dic, f)
    lock.release()  # 还钥匙


if __name__ == '__main__':
    lock = multiprocessing.Lock()  # 实例化
    for i in range(10):
        p = multiprocessing.Process(target=buy_ticket, args=(i,lock))  # 传入锁
        p.start()

进程池

在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,
并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态
生成多个进程,几十个尚可,若上百个甚至更多时,手动限制进程数量就显得特别繁琐,
此时进程池就显得尤为重要。

进程池Pool类可以提供指定数量的进程供用户调用,当有新的请求提交至Pool中时,
若进程池尚未满,就会创建一个新的进程来执行请求;若进程池中的进程数已经达到
规定的最大数量,则该请求就会等待,直到进程池中有进程结束,才会创建新的进程来
处理该请求。

第一种实现进程池的方式:自带函数
# 第一种实现进程池的方式:自带函数
import multiprocessing


def job(id):
    print("start %d...." % (id))
    print("end %d...." % (id))

if __name__ == '__main__':

    # 创建进程池对象
    pool = multiprocessing.Pool(processes=4)

    # 给进程池分配任务;
    for i in range(10):
        pool.apply_async(job, args=(i + 1,))
    pool.close()
    # 等待所有的子进程执行结束, 关闭进程池对象;
    pool.join()
    print("所有任务执行结束.....")
第二种实现进程池的方式:concurrent.futures模块
from concurrent.futures import ProcessPoolExecutor

def job(id):
    print("start %d...." % (id))
    print("end %d...." % (id))

pool = ProcessPoolExecutor(max_workers=4)
#
# for id in range(10):
#     # 分配任务给子进程, 并且返回一个Future对象;
#     f1 = pool.submit(job, args=(id))
#     # 判断子进程是否执行结束?
#     print(f1.done())
#     # 查看该子进程执行的结果
#     print(f1.result())

pool.map(job, range(10))

进程之间的通信:生产者与消费者模型

通信集中方式:

线程通信=====(队列) ---- from queue import Queue
进程池中进程通信=====(队列) — from multiprocess.Manager import Queue
多进程通信=========(队列) ---- from multiprocess import Queue
import multiprocessing
import time

class Producer(multiprocessing.Process):
    def __init__(self,queue):
        super(Producer, self).__init__()
        self.queue=queue
    def run(self):
        # 将需要通信的数据写入队列中;
        for i in range(10):
            self.queue.put(i)
            # time.sleep(0.1)
            print("传递消息, 内容为%s" %(i))
class Consumer(multiprocessing.Process):
    def __init__(self,queue):
        super(Consumer, self).__init__()
        self.queue=queue
    def run(self):
        while True:
            time.sleep(0.1)
            res=self.queue.get()
            print("接受到另一进程传递的数据: %s" %(res))

if __name__ == '__main__':
    q =  multiprocessing.Queue()
    p1 = Producer(q)
    c1 = Consumer(q)
    p1.start()
    c1.start()
    p1.join()
    c1.join()

实例演示:实现文件的备份
import os
import time
import multiprocessing
from queue import Queue

def copyfile(oldFoldername,newFlodername,filename,queue):
    # 打开选择的目录里边的文件

    fr=open(os.path.join(oldFoldername,filename),'rb')
    fw=open(os.path.join(newFlodername,filename),'wb')
    with fr,fw:
        # 设置一个一次最大读取的数据大小
        try:
            content=fr.read(1024*3)
            # 每读取一次数据,就写入
            if content:
                fw.write(content)

            print('write %s' %(filename))
        except Exception as e:
            print('error:',e)
        else:
            queue.put(filename)

def main():
    while True:
        oldFoldername=input('请输入备份的目录名:')
        if os.path.exists(oldFoldername):
            break
        else:
            print("%s目录不存在" % (oldFoldername))
    datetime=time.strftime('%Y-%m-%d-%H-%M')
    newFoldername=oldFoldername+'_备份'+datetime
    if os.path.exists(newFoldername):
        # os.rmdir(newFolderName)  # 删除空目录
        # os.removedirs(newFolderName)
        os.system('rm -fr %s' %(newFoldername))
    os.mkdir(newFoldername)
    print('正在创建备份目录%s...'%(newFoldername))
    # 获取当前目录下所有文件名
    filenames=os.listdir(oldFoldername)
    # 队列, 存储已经备份的文件;
    # ****如果是用进程池,那么就需要使用Manager().Queue()队列才能在各子进程间通信,否则沒用
    queue=multiprocessing.Manager().Queue()
    # 设置进程池里边最大进程数
    pool=multiprocessing.Pool(4)
    for filename in filenames:
        pool.apply_async(copyfile,args=(oldFoldername,newFoldername,filename,queue))

    num=0 # 当前备份的文件数
    allNum=len(filenames) # 总备份的文件数
    while num<allNum:
        queue.get()
        num+=1
        copyrate=num/allNum
        # \r使得光标不换行;
        print('\r\r备份的进度为%.2f%%'%(copyrate*100),end='')
    pool.close()
    pool.join()
    print('备份成功')


if __name__ == '__main__':
    main()

运行结果显示:

请输入备份的目录名:/home/kiosk/桌面/test
正在创建备份目录/home/kiosk/桌面/test_备份2019-08-28-17-41...
write file1
备份的进度为25.00%write file3
备份的进度为50.00%write file4
备份的进度为75.00%write file2
备份的进度为100.00%备份成功

进程之间的通信—管道

import multiprocessing
import time

def after(conn):
    while True:
        print('接收数据:',conn.recv())

        time.sleep(1)
def before(conn):
    while True:
        data={'name':'westos','age':12}
        # data=[12,34,55]
        conn.send(data)
        print('发送数据:',data)
        time.sleep(1)
def main():
    before_conn,after_conn=multiprocessing.Pipe()
    p1=multiprocessing.Process(target=before,args=(after_conn,))
    p2=multiprocessing.Process(target=after,args=(before_conn,))

    p1.start()
    p2.start()
    p1.join()
    p2.join()
if __name__ == '__main__':
    main()


#---->:
发送数据: {'name': 'westos', 'age': 12}
接收数据: {'name': 'westos', 'age': 12}
发送数据: {'name': 'westos', 'age': 12}
接收数据: {'name': 'westos', 'age': 12}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值