第十七讲 python学习总结----进程

1、内存管理(了解)
内存:所有的程序都在内存中运行 内存分栈、堆
函数的运行都是在栈里面,(栈:先进后出),函数的执行过程就是后进先出
函数调用函数第二个函数后开辟内存空间先释放
(后进先释放)
第一个函数先开辟内存空间却要等第二个函数释放完再释放
(先进后释放)

堆:所有的对象存放的地方就都在堆里面存放

#100是对象,放在堆里 在内存中有相应的内存地址
#a是指针,放在栈里  栈存放100对应的哪个内存地址

内存:6g 8g 3g 2g
地址:为了方便管理内存,给内存的每一个字节起了一个编号,这个编号就是地址
指针:是一个变量,这个变量是用来存放地址的,(引用)
在python里面所有的变量都是指针,包括列表、元组、字典中存放的都是指针

查看内存地址,通过id查看
print(hex(id(a))) #以16进制查看a的内存地址
print(hex(id(b)))

栈空间不用管理,自动释放,堆空间需要管理
Python属于上层语言,底层已经做好了内存管理,所以不用程序猿自己管理,我们只需要了解其中的原理即可 malloc
空间需要申请和释放的

内存如何释放?当前没有程序在用时才能释放

内存释放原理:
聊天室原理:多人一起聊天 0人关闭
引用计数的概念
对象空间里面有一个引用计数,在记录当前有多少个指针指向这里,当引用计数变为0的时候,这段空间就要被销毁
程序运行结束的时候 空间也会被销毁

判断两个指针是否指向同一个地方
is和==是不一样的,is判断的是两个指针是否指向同一个地方,==判断是内容是否相同
列表:可变类型都是两个空间
字符串:不可变类型都是一个空间

深浅拷贝
一层意义:
拷贝指针叫做浅拷贝
拷贝内存叫做深拷贝
多层意义:
列表只拷贝一层,叫做浅拷贝
列表拷贝多层,里面的列表也拷贝,叫做深拷贝
import copy
lt2 = copy.deepcopy(lt1) 深拷贝
lt2 = copy.copy(lt1) 浅拷贝
lt2 = lt1.copy() 浅拷贝

这里写图片描述
这里写图片描述

#内存案例演示
#内存
#栈和堆  对象和指针
'''
a = 100   #a是指针 放在内存中的栈里面 存放的是100的内存地址
          #100是对象 放在内存的堆里面 会有一个对应的内存地址
b = 200

print(hex(id(a)))   #查看a,b的内存地址以16进制查看
print(hex(id(b)))


#列表的存放原理 见图
lt = [100, 200, 300, 400]  #lt放在栈里存放的是lt0 lt1 lt2 lt3的内存地址
                           #lt0存放的是100的内存地址 
                           #100是放在堆里面的 有内存地址
lt = 'hello'       
#列表是可变的 本来lt是指向l列表的,现在指向字符串,存放'hello'的内存地址
print(lt)

'''
#内存是如何释放的?
'''
class Dog(object):
    """docstring for Dog"""
    def __init__(self, name):
        super(Dog, self).__init__()
        self.name = name

wangcai = Dog('旺财') #wangcai是指针,存放的是Dog函数的内存地址,放在栈空间里面的,指向堆空间
                      #Dog函数是对象 放在堆空间里面 有一个内存地址
wangcai = 100         #wangcai 此时指向100的内存地址,100是常量地址是固定的
                      #那么此时,Dog函数的内存空间就会释放
'''
'''
#证明Dog函数空间已经被释放了
#__del__()函数当内存释放的时候系统会自动调用
#当内存被销毁的时候函数调用会打印'这条狗被杀了'看打印的顺序
class Dog(object):
    """docstring for Dog"""
    def __init__(self, name):
        super(Dog, self).__init__()
        self.name = name

    def __del__(self):
        print('这条狗被杀了')

wangcai = Dog('旺财') #wangcai是指针,存放的是Dog函数的内存地址,放在栈空间里面的,指向堆空间
print(100)                    #Dog函数是对象 放在堆空间里面 有一个内存地址
wangcai = 100   
print(200)

#输出结果

#100
#这条狗被杀了  此时Dog函数的内存已经被释放了
#200

'''
'''
#两个指针指向同一个对象 内存如何释放? ---->聊天室原理
class Dog(object):
    """docstring for Dog"""
    def __init__(self, name):
        super(Dog, self).__init__()
        self.name = name

    def __del__(self):
        print('这条狗被杀了')

wangcai = Dog('旺财') 
lala = wangcai  #wangcai里面存放的是Dog函数的内存地址 会给lala
                #此时有两个指针lala wangcai指向Dog函数
print(100) 
wangcai =100                 
print(200)
'''

'''
#聊天室原理:只要还有人再用就不会销毁这段空间
class Dog(object):
    """docstring for Dog"""
    def __init__(self, name):
        super(Dog, self).__init__()
        self.name = name

    def __del__(self):
        print('这条狗被杀了')

    def wangwang(self):
        print('汪汪')

wangcai = Dog('旺财') 
lala = wangcai
dudu =lala              #此时三个指针wangcai lala dudu指向Dog函数

lala.wangwang()
print(100)
wangcai = 100   #wangcai指针指向100 还有两个指针指向Dog函数  不释放
print(200)
print('lala')
lala = 200     #lala指针指向200  还有一个指针指向Dog函数  不释放
print('lala')
print('dudu')
dudu = 100     #dudu指针指向100 还有0个指针指向Dog函数  释放空间
print('dudu')
'''
'''
#判断两个指针是否指向同一个地方
#两个指针指向同一个空间
class Dog(object):
    """docstring for Dog"""
    def __init__(self, name):
        super(Dog, self).__init__()
        self.name = name

    def __del__(self):
        print('这条狗被杀了')

    def wangwang(self):
        print('汪汪')

wangcai = Dog('旺财') 

lala = wangcai  #没开辟新空间

print (lala.name)
wangcai.name = 'hehe'  #只是修改了wangcai.name 并未修改lala.name为什么也会变?
print(lala.name)
 #由于wangcai 和lala 指向同一个对象 操作同一个目标 name在空间里面放着 
 #wangcai.name修改了 lala.name也会被修改

#两个指针指向不同的目标
class Dog(object):
    """docstring for Dog"""
    def __init__(self, name):
        super(Dog, self).__init__()
        self.name = name

    def __del__(self):
        print('这条狗被杀了')

    def wangwang(self):
        print('汪汪')

wangcai = Dog('旺财') 

lala = Dog('旺财') #此时只有wangcai.name修改了 lala.name并没有修改
                   #此时开辟了新的空间

print (lala.name)
wangcai.name = 'hehe'  
print(lala.name)

'''
'''

#列表如何判断是否指向同一空间?
lt1 = [100, 200, 300]
lt2 = [100, 200, 300]
# print(id(lt1))
# print(id(lt2))
if lt1 == lt2:     #只是判断内容是否相等?
    print('相等')
else:
    print('不相等')

if lt1 == lt2:     #判断是否同一个空间?
    print('相等')
else:
    print('不相等')



#字符串如何判断是否指向同一段空间?
str1 = 'hello'
str2 = 'hello'
if str1 == str2:     
    print('相等')
else:
    print('不等')

if str1 is str2:
    print('相等')
else:
    print('不等')
#输出都是相等 原因字符串是不可变类型 内存地址是固定的  不会再开辟空间



#整形如何判断是否指向同一段空间?
a = -5
b = -5
if a is b:
    print('相等')
else:
    print('不相等')
#-5及以上一个内存相等,-5以下开辟两个内存不相等

'''

#拷贝的两种方式
#第一多一个指针指向
#第二拷贝

#深浅拷贝
'''
#一层意义上的深浅拷贝
#浅拷贝
lt1 = [100, 200, 300]
lt2 = lt1         #多一个指针指向同一个空间称浅拷贝
lt1[0] = 'hello'  #一个改了另一个也会改
print(lt1)
print(lt2)

#深拷贝
lt1 = [100, 200, 300]
lt2 = lt1.copy()    #重新开辟一个空间,拷贝    
lt1[0] = 'hello'     #一个改了另外那个不会改
print(lt1)
print(lt2)
 '''
#两层意义上的深浅拷贝  多层意义上的深浅拷贝

#浅拷贝
lt1 = [['kobe', 'lebran', 'wade'], 200, 300]
lt2 = lt1.copy() #栈空间lt[0][0]没有拷贝即只拷贝外面没有全部拷贝
#lt2 = copy.copy(lt1)
lt1[0][0] = 'hello' #一个变了,另外的也会变
print(lt1)
print(lt2)
#原理见图形

#深拷贝
import copy
lt1 = [['kobe', 'lebran', 'wade'], 200, 300]
lt2 = lt1.deepcopy(lt1) #栈空间lt[0][0]也会拷贝即全部拷贝
lt1[0][0] = 'hello' #一个变了,另外的不会变
print(lt1)
print(lt2)




2、进程
多任务
生活中,好多例子,唱歌跳舞,开车,抽烟聊天
代码中,唱歌跳舞例子

#进程 多任务同时进行
#唱歌跳舞的例子
#边唱边跳

import time

def sing():
    for x in range(10):
        print('我在唱青藏高原')
        time.sleep(1)

def dance():
    for x in range(10):
        print('我在跳钢管舞')
        time.sleep(1)

if __name__ == '__main__':
    sing()
    dance()
#代码运行会先执行sing函数,执行完毕之后再执行dance函数
#也就是说先唱后跳
#无法完成边唱边跳的要求那么,怎样实现边唱边跳呢?

操作系统
可以实现多任务,可以听音乐、可以聊天、写代码
计算机在执行的时候只能执行一种运算
但是通过
cpu快速的切换任务,达到多任务同时进行的目的
打开一个应用 一个任务,就是一个进程
代码和进程
编写的代码,在没有运行之前,我们称之为程序
运行的时候,就是一个进程
进程的创建(process)
mac:unix
乌班图 Ubuntu:linux(类unix)
类unix系统的创建方式
pid = os.fork()
进程号:pid,系统都是根据进程号来管理进程的
fork函数调用一次,返回两次,如果主进程执行,返回的pid是子进程id,如果子进程执行,返回的pid是0
获取当前进程id号:os.getpid()
获取当前进程的父进程的id号:os.getppid()
windows的创建方式
from multiprocessing import Process

#通过进程实现边唱歌边跳舞-----unix系统下

#主进程是当前代码运行,子进程就是通过主进程创建的

import os
pid = os.fork() #pid== process id 进程号
                #普通的函数调用之后会返回一次,fork函数调用之后会返回两次
                #主进程在跑的时候会返回子进程的pid 
                #子进程在跑的时候会返回0,不是子进程的ID号
if pid == 0:
    print('主进程在跑')
else:
    print('子进程在跑')
#Unix系统下运行
#会发现if和else都在跑,会有两个进程一个跑if,一个跑else


import os
pid = os.fork() 

if pid == 0:

    print('子进程在跑')
    print('子进程的pid为%s'%os.getpid())  #获取当前进程的ID号os.getpid()
    print('子进程的父进程pid为%s'%os.getppid())#子进程的父进程就是主进程

else:                                     #获取当前进程的父进程的ID号os.getppid( ) parrent pid
    print('父进程在跑')
    print('子进程的pid为%s'%pid)
    print('父进程的pid为%s'%os.getpid())
#通过进程实现边唱歌边跳舞----windows系统下面向过程和面向对象两种方式
#面向过程的写法
#第一步  导入库  设置入口
#格式:(面向对象必须要按照这个格式进行创建进程)
'''
#导入库  设置入口
from multiprocessing import Process

if __name__ == '__main__':
    main()
'''
#第二步创建一个进程
'''
from multiprocessing import Process

def lala():
    #pass
    print('lala进程在执行')

if __name__ == '__main__':

#创建一个进程
        #创建进程和创建对象是一样的通过变量进行创建,里面有参数
        #target 创建进程要执行的函数 target=lala  创建一个进程执行lala函数
        #name是给这个进程起个名字
    p = Process(target=lala,name='啦啦') #此时创建了两个进程一个主进程一个lala进程
    print('主进程在执行')                #但是只执行了主进程lala进程并没有执行
'''                                      #原因是lala进程必须要启动才行
#第三步 启动一个进程
'''
 #如何启动一个进程
from multiprocessing import Process

def lala():
    print('lala进程在执行')

if __name__ == '__main__':
    p = Process(target=lala,name='啦啦') 
    #启动一个进程
    p.start()
    print('主进程在执行') 
'''
#第四步 主进程等待子进程结束再执行
'''
from multiprocessing import Process
import time

def lala():
    for x in range(10):
        print('lala进程在跑第%d次' % x)  #让子进程走一会儿
        time.sleep(1)

if __name__ == '__main__':
    p = Process(target=lala,name='啦啦') 
    p.start() #运行的时候子进程是通过主进程创建出来的,主进程会先执行,子进程再执行,这样就会主进程先结束
    #若主进程先结束那么子进程可能就找不到了变成僵尸进程
    #让主进程等待子进程运行完成完毕之后再执行
    p.join()

    print('主进程和子进程全部结束')


'''
#最终代码
'''
from multiprocessing import Process
import time

def lala():
    for x in range(10):
        print('lala进程在跑第%d次' % x)  #让子进程走一会儿
        time.sleep(1)

if __name__ == '__main__':
    p = Process(target=lala,name='啦啦') 
    p.start() 
    for x in range(10):
        print('主进程在跑第%d次' % x)#让主进程走一会儿
        time.sleep(1)
    p.join()

    print('主进程和子进程全部结束')


'''
#总结
'''
from multiprocessing import Process

def lala():
    #pass
    print('lala进程在执行')

if __name__ == '__main__':
    #创建进程和创建对象是一样的通过变量进行创建,里面有参数
    #target 创建进程要执行的函数 target=lala  创建一个进程执行lala函数
    #name是给这个进程起个名字
    p = Process(target=lala,name='啦啦') #此时创建了两个进程一个主进程一个lala进程
    print('主进程在执行') 
'''

#进程之间传递参数
'''
from multiprocessing import Process
import time

def lala(a):                            #主进程给子进程传递参数a就是100
    # print('lala进程在执行')
    print(a)
    for x in range(3):
        print('lala进程在跑第%d次' % x)
        time.sleep(1)

if __name__ == '__main__':
    # target: 创建进程要执行的函数
    # name:给进程起一个名字
    # args: 给子进程传递参数  是一个元组  #主进程给子进程传递参数100
    p = Process(target=lala, name='啦啦', args=(100,))  #args=(100,)元组中一个参数的格式要有逗号
    # 启动一个进程
    p.start()
    for x in range(3):
        print('主进程在跑第%d次' % x)
        time.sleep(1)
    # print(p.name)
    # 让主进程等待子进程结束之后在执行
    p.join()
    print('主进程和子进程全部都结束')
'''

#总结
#第一步导入库 创建入口
#第二步创建进程 启动一个进程 让主进程等待子进程结束之后再结束
#第三步 写进程里面的目标函数

面向过程
见代码
p.start() 启动进程
p.join() 让主进程等待子进程结束之后再执行
p.terminate() 让子进程终止
p = Process(target=xx, name=xx, args=(xx, xx))
target: 子进程要执行的函数
name:进程的名字
args:给子进程传递的参数
面向对象
见代码
获取进程id号:os.getpid()
获取进程父id号:os.getppid()
写一个类继承自Process,重写run方法

#windows下多进程-----面向对象的写法
#通过类来创建一个进程
#面向对象的类是自己写的,面向过程是自带的

'''
from multiprocessing import Process
import time, os

class MyProcess(Process):
    """docstring for MyProcess"""
    def __init__(self, name):
        super(MyProcess, self).__init__()
        self.name = name

    def run(self):
        for x in range(5):
            print('子进程在跑')
            time.sleep(1)

if __name__ == '__main__':
    p = MyProcess('小进程')

    p.start()

    for x in range(3):
        print('主进程在跑')
        time.sleep(1)

    p.join()
    print('主进程结束')
'''

'''
#获取进程ID号os.getpid()获取当前进程ID号, os.getppid()获取父进程的ID号
#终止子进程

from multiprocessing import Process
import time, os

class MyProcess(Process):
    """docstring for MyProcess"""
    def __init__(self, name):
        super(MyProcess, self).__init__()
        self.name = name

    # 重写一个run方法,这个run方法就是进程执行的函数
    #通过类创建一个进程,进程默认执行的就是run方法不能改名字
    def run(self):
        print('子进程的id为%s,主进程的id为%s' % (os.getpid(), os.getppid()))
        for x in range(5):
            print('子进程在跑')
            time.sleep(1)

if __name__ == '__main__':
    print('主进程id号为%s' % os.getpid())
    p = MyProcess('小进程')
    p.start()
    for x in range(3):
        print('主进程在跑')
        time.sleep(1)

    # 终止子进程 
        #主进程跑3次子进程跑5次肯定主进程先跑完主进程跑完后终止子进程
    p.terminate()

    print('主进程结束')
'''

全局变量
主进程和子进程不共享全局变量,只要创建进程,就会将代码复制一份,主进程里面有代码,子进程里面也有代码,他们都拥有自己的全局变量

#全局变量和局部变量
#进程之间是否共享全局变量和局部变量?

#思路
#demo函数修改全局变量那么子进程运行会修改子进程的全局变量
    #若主进程的全局变量也修改了说明主进程和子进程共享全局变量
    #若主进程的全局变量没有修改说明子进程和主进程不共享全局变量

#代码

from multiprocessing import Process
import os

count = 1000 #全局变量

def demo():
    print('子进程%d在运行' % os.getpid())

#修改全局变量
    global count
    count += 100

    print('子进程里面的count为%d' % count)

if __name__ == '__main__':
    # 创建一个进程
    p = Process(target=demo)
    # 启动一个进程
    p.start()
    # 让主进程等待子进程结束之后再结束
    p.join()

    print('主进程里面的count为%d' % count)
    print('主进程子进程都结束')



#输出结果表明 主进程和子进程不共享全局变量
#创建进程之后全局变量在主进程中会有一份,在子进程中也会有一份,子进程的全局变量是子进程的全局变量,主进程是主进程的

进程池(pool)
见代码

#进程池
#进程池也是用来创建进程的,能一次创建多个进程
#思路
#pol = Pool(3)说明只能创建三个进程  向池子中添加任务创建无数个任务会创建无数个进程
#最终通过ID号判断有几个进程

from multiprocessing import Pool
import os, time, random

def test(name):
    print('子进程%s开始运行,其id号为%s' % (name, os.getpid()))

    lt = [1, 2, 3]
    time.sleep(random.choice(lt))


if __name__ == '__main__':
    print('主进程开始执行,id号为%d' % os.getpid())
#创建进程池
    pol = Pool(3)
    # 3代表最多创建3个进程,
    #向池子中添加任务,添加一个任务就会创建一个进程,
    #如果进程数没有超过3,直接创建,
    #如果进程数超过3了,等待里面的进程结束,再创建

    for x in ['张飞', '赵云', '关羽', '黄忠', '典韦', '貂蝉', '吕布', '刘备']:
# 向池子中添加任务
        pol.apply_async(test, args=(x,))

# 用完之后,关闭池子
    pol.close()

    pol.join()# 让主进程等待子进程结束
    print('主进程、子进程全部结束')

进程间通信(队列queue)
先进先出

3、单元测试

猜你喜欢

转载自blog.csdn.net/weixin_41853490/article/details/81027811
今日推荐