爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 13312|回复: 5

[源代码] Python之进程的学习

[复制链接]

新浪微博达人勋

发表于 2020-12-23 15:56:49 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
本帖最后由 15195775117 于 2020-12-23 16:03 编辑

一、需求缘起

昨天写了个FTP文件传输程序,19.1个小时拷来了1.17G的数据,
17k/s的速度,闻者伤心,见者流泪!
但是,这并非完全是网络的原因,我拷的文件体积小、数量庞大,大量的时间应该消耗在了频繁的文件写入过程。
关于写文件过程的耗时,以前我也发现过,是不可忽视的。
由于现在我还不知道如何实现FTP远程文件夹压缩打包,所以眼下我能想到的加速方法就只有多进程、多线程了。

二、初识进程

资源管理器进程.jpg

什么是进程(Process)?
资源管理器中,进程就是各种运行中的程序exe
所谓多任务,即多进程
进程工具有2个:模块multiprocessing,Pool进程池
以下程序研究multiprocessing

from multiprocessing import Process
import time

# Process类表示进程对象
# 语法:
# Process(groug,#默认None
#         target,#当前进程启动时执行的可调用对象
#         name,#当前进程实例的别名
#         args,#传递给target函数的参数元组
#         kwargs)#传递给target函数的参数字典

#子进程x=5表示每隔2s从1打印到5
def test(x):
    print('子进程开始',x)
    for i in range(1,x+1):
        print(i)
        time.sleep(2)
    print('子进程结束')

def main():
    print('主进程开始')
    p=Process(target=test,args=(5,))
    p.start()#启动子进程,执行test
    print('进程是否在执行中:',p.is_alive())
    print('当前进程别名:',p.name)#别名格式默认为Process-N
    print('当前进程PID值:',p.pid)
    #p.join([3]) #等待进程结束,等3秒(怎么用?)
    #p.run() #如果没有给定target参数,使用start方法时将执行p的run方法(?)
    time.sleep(3)
    print('终止进程')
    p.terminate()

if __name__ == '__main__':
    main()
    print('结束')

#在命令行执行才会显示子进程的内容,
#__name__ == '__main__'也是必须的

# 打印结果:
# 主进程开始
# 进程是否在执行中: True
# 当前进程别名: Process-1
# 当前进程PID值: 3612
# 子进程开始 5
# 1
# 2
# 终止进程
# 结束





评分

参与人数 1金钱 +2 收起 理由
好运人 + 2 很给力!

查看全部评分

密码修改失败请联系微信:mofangbao

新浪微博达人勋

 楼主| 发表于 2020-12-23 16:53:32 | 显示全部楼层
进程相关函数

os.getpid()返回值:返回当前进程的PID

os.getppid()
返回值:返回父进程PID

os._exit(0)
结束进程

sys.exit([status])
退出进程,参数:整数:表示退出状态,字符串:表示退出时,打印内容


密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2020-12-24 17:16:19 | 显示全部楼层
三、固定套路

from multiprocessing import Process
import time,os
import random

#该函数留给进程使用,n表示读取文件的次数:
def f(n):
    for i in range(n):
        file=open(r'C:\Users\Administrator\Desktop\帕金森定律.txt','r')
        file.close()
        
if __name__=='__main__':
    print('父进程PID:',os.getpid())
   
    t1=time.time() #多进程计时开始
   
    # 分5个进程读文件2000次:
    for num in range(5):
        exec("p"+str(num)+"=Process(target=f,args=(5000,))")  #创建进程
    for num in range(5):
        exec("p"+str(num)+".start()") #启动进程
    for num in range(5):
        exec("p"+str(num)+".join()")  #等待进程结束
    t2=time.time() #多进程计时结束
    print('多进程耗时%0.2fs'%(t2-t1))
   
    t1=time.time() #单进程计时开始
    #一口气读2000*5次:
    for i in range(5):
        f(5000)
    t2=time.time() #单进程计时结束
    print('单进程耗时%0.2fs'%(t2-t1))

结果:
父进程PID: 8920
多进程耗时2.66s
单进程耗时5.66s


密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2020-12-25 11:31:55 | 显示全部楼层
多进程的性能压力

前两天开始使用多进程进行FTP文件传输,速度就快多了!
一开始我还担心服务器性能跟不上,现在胆子也大了。
现在我正在用820个进程来传输数据,感觉对CPU压力不大,只是内存占用比较多
比较来看,昨天400多个进程是10多G内存,现在820个进程是20多G,看来进程数跟内存正比,
如果想把内存用满,可以使用820*4=3280个进程
当然,还得看对方服务器能不能接受。

820个进程.jpg

密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-5 14:52:00 | 显示全部楼层
本帖最后由 15195775117 于 2021-1-5 15:29 编辑

进程间通信的渠道---队列Queue

进程间的通信,使用全局变量无法实现,使用的是队列(Queue)和管道(Pipes),这里只演示队列
560008989.jpg


队列的基础使用方式示例:

from multiprocessing import Queue

#Queue是队列的类,其方法如下:
#Queue.qsize():返回当前队列包含的消息数量
#Queue.empty():队列是否为空,返回值为逻辑值
#Queue.full():队列是否满,返回值为逻辑值
#Queue.get_nowait():获取队列的一条消息然后移除
#Queue.put_nowait('xxx'):写入'xxx'

if __name__=='__main__':
    q=Queue(3)#最多接收3个消息,q=Queue()表示无上限
    q.put('111')
    q.put('222')
    print(q.full())
    q.put('333')
    print(q.full())
    try:
        q.put_nowait('444')
    except:
        print('队列已满')
   
    for i in range(q.qsize()):
        x=q.get_nowait()
        print('获取消息:'+x+',队列消息数=',q.qsize())
   
    print('队列是否满:',q.full())

输出:

False
True
队列已满
获取消息:111,队列消息数= 2
获取消息:222,队列消息数= 1
获取消息:333,队列消息数= 0
队列是否满: False


密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-5 15:28:21 | 显示全部楼层
使用队列实现进程间通信的案例

from multiprocessing import Process,Queue
import time

#向队列写入消息:
def write_task(q):
    if not q.full():
        for i in range(5):
            message='消息'+str(i)
            q.put(message)
            print('写入'+message)

#从队列读取消息:
def read_task(q):
    time.sleep(1)
    while not q.empty():
        print('读取',q.get(True,2))

if __name__=='__main__':
    q=Queue()
    pw=Process(target=write_task,args=(q,))
    pr=Process(target=read_task,args=(q,))
    pw.start()
    pr.start()
    pw.join()
    pr.join()

输出:
写入消息0
写入消息1
写入消息2
写入消息3
写入消息4
读取 消息0
读取 消息1
读取 消息2
读取 消息3
读取 消息4

我的疑惑:
队列这种数据结构非常特殊,应该是应用于特定场景的,网上说它“广泛应用在各种 广度优先搜索中”,
虽然它能实现进程间的通信,但总觉得不合习惯,应用价值还得在项目中体会。


密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表