目录

  • 创建进程
  • 进程实现并发
  • 进程间数据默认隔离
  • 进程对象属性和方法
  • 僵尸进程与孤儿进程
  • 守护进程
  • 互斥锁

创建进程


创建进程的方式有两种,第一种就是双击桌面的一个应用图标即可,这个不用讲大家都会,不会的可以百度!!!我们主要讲讲第二种在python中用代码创建。

创建进程的本质:在内存中申请一块内存空间用于运行相应的程序代码。一个进程对应在内存中就是一块独立的内存空间,多个进程对应在内存中就是多块独立的内存空间,进程与进程之间数据默认情况下是无法直接交互,如果想交互可以借助于第三方工具、模块。以下是代码创建进程的三种方式。

第一种方法

from multiprocessing import Process
import time

def task(name):  
	print(f"my name is {name},启动时间")
	time.sleep(2)
	print(f"my name is {name},停止时间")

if __name__ == '__main__':
# 1 创建一个对象
	p = Process(target=task, args=('jason',))
	# 容器类型哪怕里面只有1个元素 建议要用逗号隔开 args=	('jason',)
	# 2 开启进程
	p.start() # 告诉操作系统帮你创建一个进程 异步
	print('主进程')

第二种方法

from multiprocessing import Process
import time

class MyProcess(Process):  
	def run(self):
		print('hello bf girl,启动时间')
		time.sleep(1)
		print('get out!,停止时间')

if __name__ == '__main__':
	p = MyProcess()
	p.start()
	print('主进程')

第三种方法

# join是让主进程等待子进程代码运行结束之后,再继续运行。不影响其他子进程的执行
from multiprocessing import Process
import time

def task(name, n):
    print(f'{name} is running')
    time.sleep(n)
    print(f'{name} is over')

if __name__ == '__main__':
    p1 = Process(target=task, args=('jason', 1))
    p2 = Process(target=task, args=('tony', 2))
    p3 = Process(target=task, args=('kevin', 3))
    start_time = time.time()
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    end_time = time.time() - start_time
    print('主进程', f'总耗时:{end_time}')  # 主进程 总耗时:3.015652894973755
    # 如果是一个start一个join交替执行 那么总耗时就是各个任务耗时总和

强调:不同的操作系统创建进程的要求不一样
在windows中创建进程是以导入模块的方式进行 所以创建进程的代码必须写在__main__子代码中
否则会直接报错 因为在无限制创建进程
在linux和mac中创建进程是直接拷贝一份源代码然后执行 不需要写在__main__子代码中

python 创建独立进程 python创建进程的方法_python 创建独立进程

进程实现并发


将与客户端通信的代码封装成一个函数,之后每来一个客户端就创建一个进程专门做交互。

# 服务端
import socket
from multiprocessing import Process

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

# 将服务客户端的代码封装成函数(通信代码)
def talk(sock):
    while True:
        data = sock.recv(1024)
        print(data.decode('utf8'))
        sock.send(data.upper())

if __name__ == '__main__':
    while True:
        sock, addr = server.accept()
        p = Process(target=talk, args=(sock, ))
        p.start()
# 客户端1
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    client.send(b'hello big baby~')
    data = client.recv(1024)
    print(data.decode('utf8'))
# 客户端2
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    client.send(b'hello tony~')
    data = client.recv(1024)
    print(data.decode('utf8'))

进程间数据默认隔离


from multiprocessing import Process

money = 999

def task():
    global money  # 局部修改全局不可变类型
    money = 666

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()  # 确保子进程代码运行结束再打印money
    print(money)  # 999
'''可以通过一些技术打破以通过一些手段默认的隔离'''

python 创建独立进程 python创建进程的方法_子进程_02

进程对象属性和方法


进程号在Windows上可以通过命令窗口tasklist集中查询PID,在mac系统上可以通过ps -ef查看。

python查看进程号的方法:

1.current_process函数
    from multiprocessing import Process, current_process
    current_process().pid
    获取进程号的用处之一就是可以通过代码的方式管理进程
    windows  	    taskkill关键字  结束进程
    mac/linux  		kill关键字      结束进程
2.os模块
    os.getpid()     获取当前进程的进程号
    os.getppid()    获取当前进程的父进程号

杀死子进程

terminate()

判断子进程是否存活

is_alive()

僵尸进程与孤儿进程


僵尸进程

所有的子进程在运行结束之后都会变成僵尸进程,还保留着pid和一些运行过程的中的记录便于主进程查看(短时间保存),这些信息会被主进程回收(僵尸彻底死了)。主进程回收方式:主进程正常结束,调用join方法。

孤儿进程

子进程存活着,父进程意外死亡,子进程会被操作系统自动接管(儿童福利院)。

守护进程


守护即死活全部参考守护的对象,对象死立刻死。

from multiprocessing import Process
import time

def task(name):
    print(f'大内总管:{name}正常活着')
    time.sleep(3)
    print(f'大内总管:{name}正常死了')

if __name__ == '__main__':
    p = Process(target=task, args=('赵公公',))
    # 必须写在start前面
    p.daemon = True  # 将子进程设置为守护进程:主进程结束 子进程立刻结束
    p.start()
    print('皇帝Jason寿终正寝')

python 创建独立进程 python创建进程的方法_json_03

互斥锁


当多个进程操作同一份数据的时候会造成数据的错乱!!!这个时候就需要对数据进行加锁处理,讲并发变成串行,虽然牺牲了效率但是保证了数据的安全。

互斥锁并不能轻易使用,容易造成死锁现象,互斥锁只在处理数据的部分加锁,不能什么地方都加,严重影响程序的效率。

from multiprocessing import Process, Lock
mutex = Lock()   # 产生互斥锁
mutex.acquire()  # 抢锁
mutex.release()  # 放锁

代码模拟抢票,抢票就是对票的数据进行了加锁,可以显示到余票,但不一定抢的到。

import json
from multiprocessing import Process, Lock
import time
import random


# 查票
def search(name):
    with open(r'ticket_data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print(f'{name}查询当前余票:%s' % data.get('ticket_num'))


# 买票
def buy(name):
    '''
    点击买票是需要再次查票的 因为期间其他人可能已经把票买走了
    '''
    # 1.查票
    with open(r'ticket_data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    time.sleep(random.randint(1, 3))
    # 2.判断是否还有余票
    if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'ticket_data.json', 'w', encoding='utf8') as f:
            json.dump(data, f)
        print(f'{name}抢票成功')
    else:
        print(f'{name}抢票失败 没有余票了')


def run(name, mutex):
    search(name)
    # 只需要把买票环节变成串行即可
    mutex.acquire()  # 抢锁
    buy(name)
    # mutex.release()  # 放锁


# 模拟多人同时抢票
if __name__ == '__main__':
    # 互斥锁在主进程中产生一把 交给多个子进程用
    mutex = Lock()
    for i in range(1, 10):
        p = Process(target=run, args=('用户:%s' % i, mutex))
        p.start()