Python基础之进程、并发、阻塞

发布时间 2023-07-11 17:44:40作者: Way*yy

进程的概念

什么是进程?
	正在进行的一个过程或者说是一个任务,而负责执行任务的是CPU
	举例(单核+多道,实现多个进程的并发执行)
    """
    	Eg:
    		我在同一个时间段内有多个任务,比如做饭、学习、打游戏、刷视频
    		但是同一个时间我只能做一件事(CPU同一时间只能干一个活),如何完成多任务并发执行的效果?
    		我做一会饭,再去学一会习,再打一会游戏。。。等等,这就保证每个任务都在进行中了
    """

进程和程序的区别:
	1、程序仅仅是一堆代码,它没有生命周期,
	2、进程则是程序运行的过程,他是有生命周期的,即程序结束进程死亡
    
    "进程中最重要的就是线程,进程中没有线程是没有意义的,一个进程中可以有多个线程,但是一个进程中最少要有一个线程"
    
    进程和线程都是由操作系统来调度的
    进程则是操作系统的一个独立单元
    
    举例:
    	我正在做一道菜,首先要有一道菜谱,其次就是做菜的原材料(白菜、蒜泥、肉末等等)
        在这个例子中:
            菜谱就是程序
            "我"就是CPU
            原材料就是输入的数据
        	我阅读菜谱以及做菜的过程就是进程
	"""需要强调的是:同一个程序执行两次,那也是两个进程,比如打开暴风影音,虽然都是同一个软件,但是一个可以播放苍井空,一个可以播放饭岛爱。"""
    
    补充:CPU的工作机制
        1. 当CPU遇到I/O操作的时候,会剥夺CPU的执行权限
        2. 当遇到的任务需要占用大量的时间的时候,也会剥夺执行权限

        """其实CPU的工作机制是来回切换做到的"""

        I/O密集型:
            input  output
           """遇到阻塞,但是不需要占用大量的CPU资源,需要等待,比如:sleep""" 	

        计算密集型
            """没有遇到阻塞,但是需要占用大量的CPU资源,也不需要等待"""

并发与并行

无论是并发还是并行,在用户看来都是"同时"运行的,不管是进程还是线程,都只是一个任务而已,真干活的还是CPU,CPU来做这些任务,但是一个CPU同一时间内只会执行一个任务。

并发:
	并发就是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
    
    Eg:
        你是一个cpu,你同时谈了三个女朋友,每一个都可以是一个恋爱任务,你被这三个任务共享,要玩出并发恋爱的效果,应该是你先跟女友1去看电影,看了一会说:不好,我要拉肚子,然后跑去跟第二个女友吃饭,吃了一会说:那啥,我去趟洗手间,然后跑去跟女友3开了个房
        
并行:"在同一时刻",同时执行多个任务,前提是多核CPU
	有四个核,六个任务,这样同一时间有四个任务被执行,假设分别被分配给了cpu1,cpu2,cpu3,cpu4, 一旦任务1遇到I/O就被迫中断执行,此时任务5就拿到cpu1的时间片去执行,这就是单核下的多道技术,而一旦任务1的I/O结束了,操作系统会重新调用它(需知进程的调度、分配给哪个cpu运行,由操作系统说了算),可能被分配给四个cpu中的任意一个去执行

同步异步阻塞非阻塞

"""描述的是任务的提交方式"""
同步:
	任务提交以后,原地等待任务的返回结果,等待的过程中不做任何事(干等)
    "程序层面上表现的感觉就是卡住了"
异步:
	任务提交之后,不原地等待任务的返回结果,直接去做其他的事
    那么提交的任务结果如何获取?
    任务的返回结果会有一个异步回调机制自动处理
    
"描述的是程序运行状态"
阻塞:阻塞态
非阻塞:就绪态、运行态

理想状态:我们应该让我们的写的代码永远处于就绪态和运行态之间切换

"上述概念的组合:最高效的一种组合就是异步非阻塞"

开启进程的两种方式

第一种:

from multiprocessing import Process
import time


def index(name):
    print(f"这是{name}")
    time.sleep(3)
    print("from index")


#  开启进程必须要使用__main__要不然会报错
if __name__ == '__main__':
    
    """
    参数:
        group=None, target=None, name=None, args=(), kwargs={},
                     *, daemon=None

        每一个进程都有:进程名,进程id等属性
        name: 代表的是进程的名字
         args=(), 传参数的 
         kwargs={},
         daemon:守护进程
    """
    
    #  实例化一个类得到一个对象
    p = Process(target=index, args=('kevin',))
    #  容器类型哪怕里面只有一个元素,建议也要使用逗号隔开
    #  2、开启进程
    p.start()  # 告诉系统帮助你开启一个进程    异步
    
    """
        执行结果:
            这是kevin
            from index
    """
    
第二种:
	
	from multiprocessing import Process
    import time


    class MyProcess(Process):
        def run(self, ):
            print("from run")
            time.sleep(3)
            print("from index")


    if __name__ == '__main__':
        p = MyProcess()
        p.start()

    """
        执行结果:
            from run
            from index
    """

守护进程

from multiprocessing import Process
import time


def index(name):
    print(f"这是{name}")
    time.sleep(3)
    print("from index")


#  开启进程必须要使用__main__要不然会报错
if __name__ == '__main__':
    #  实例化一个类得到一个对象
    p = Process(target=index, args=('kevin',))
    #  容器类型哪怕里面只有一个元素,建议也要使用逗号隔开
    # 开启守护进程
    p.daemon = True
    #  2、开启进程
    p.start()  # 告诉系统帮助你开启一个进程    异步
    print("先执行了这里")

    """
        没有开启守护进程的执行结果:
                        先执行了这里
                        这是kevin
                        from index
        现在的现象是:主进程代码先执行,然后执行子进程里的代码,并且主进程代码执行完毕之后,子进程的代码并没有结束
        
        开启守护进程之后的结果:
                        先执行了这里
    """
    
守护进程的作用是什么呢 :
	作用是主进程结束了,子进程也会立马结束不再执行

方法介绍

    # p.terminate()  # 杀死进程
    # # True
    # import time
    # time.sleep(1)
    #
    # # False
    # print(p.is_alive())  # 查看p进程是否存活

    # join
    # 现在让你先执行子进程中的代码,在执行主进程中的代码?
    p.join()  # 先等待子进程执行完毕,在执行主进程

总结

"""
创建进程就是在内存中申请一块内存空间将需要运行的代码丢进去
一个进程对应在内存中就是一块独立的内存空间
多个进程对应在内存中就是多块独立的内存空间
进程与进程之间数据默认情况下是无法直接交互,如果想交互可以借助于第三方工具、模块
"""

join方法

join方法是让主进程等待子进程代码运行结束以后,再继续执行,不影响其他子进程的执行

from multiprocessing import Process
import time


def index(name):
    print(f'name:{name}')
    time.sleep(3)
    print("from index")


if __name__ == '__main__':
    p = Process(target=index, args=("kevin",))
    p1 = Process(target=index, args=("tom",))
    p2 = Process(target=index, args=("tank",))
    p.start()
    p.join()
    p1.start()
    p1.join()
    p2.start()
"""
    执行结果:
        name:kevin
        from index
        name:tom
        from index
        name:tank
        from index
    
    也就是说join方法会在一个对象执行完所有子进程以后再去执行主进程
"""

开启多进程

from multiprocessing import Process
import time


def index(i):
    print(f"index:{i}")
    time.sleep(1)


if __name__ == '__main__':
    satrt = time.time()
    p_list = []
    # 开启多进程以后他就是无序的
    for i in range(5):
        p = Process(target=index, args=(i,))
        #  开启进程
        p.start()
        #  将得到的进程放到定义好的列表中
        p_list.append(p)
	
    #  遍历列表,拿出来每一个子进程
    for j in p_list:
        j.join()
    end = time.time()
    print(f"time:{end - satrt}")  # time:1.1487295627593994
"""
    初次执行结果:
        index:0
        index:1
        index:3
        index:2
        index:4
"""
"""
    多进程:
        index:0
        index:1
        index:3
        index:2
        index:4
"""

进程锁

锁:是为了保证数据的安全

from multiprocessing import Process
from multiprocessing import Lock


def index(i, lock):
    # 上锁
    lock.acquire()
    print(f"from {i}个进程进来了")
    print(f"from {i}个进程出去了了")
    # 解锁
    lock.release()


if __name__ == '__main__':
    lock = Lock()
    for i in range(5):
        p = Process(target=index, args=(i, lock))
        p.start()
        p.join()

"""
执行结果:
    from 0个进程进来了
    from 0个进程出去了了
    from 1个进程进来了
    from 1个进程出去了了
    from 2个进程进来了
    from 2个进程出去了了
    from 3个进程进来了
    from 3个进程出去了了
    from 4个进程进来了
    from 4个进程出去了了
"""

进程之间的相互隔离

# 进程是可以开启多个的,进程与进程之间是相互独立的,互补影响,进程是操作系统的一个独立单元
一个进程崩溃了,其他的进程不收影响

"""在一个进程中不能修改另外一个进程的数据,言外之意是进程之间的数据是隔离的,互补影响"""

from multiprocessing import Process


money = 100


def task():
    global money  # 局部修改全局
    money = 666
    print('子',money)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print(money) # 100

利用多进程实现TCP协议下的高并发程序

#############################服务端#################################
from multiprocessing import Process
import socket


def task(socker):
    try:
        while True:
            # 接收客户端发来的消息
            f_date = socker.recv(1024)

            # 判断接收到的数据是否为空
            if len(f_date) == 0:
                continue

            # 打印客户端的消息
            print(f"这是客户端发来的消息{f_date.decode('utf8')}")

            # 给客户端一个回馈信息
            socker.send(f_date)

        # 关闭服务
        socker.close()
    except Exception as e:
        print(e)


if __name__ == '__main__':
    while True:
        #  1、实例得到一个对象
        sever = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        #  2、绑定一个地址
        sever.bind(("127.0.0.1", 8001))

        # 3、监听客户的个数
        sever.listen(4)

        # 4、等待客户端消息
        socker, addr = sever.accept()

        # 5、创建一个多项成
        f = Process(target=task, args=(socker,))

        # 6、开启多线程
        f.start()

 #############################客户端#################################
import socket

# 得到一个实例化对象
client = socket.socket()

# 绑定服务端IP
client.connect(("127.0.0.1", 8001))

# 让用户可以一直给服务端发消息
while True:
    # 让用户自己输入想要发送的信息
    cmd = input("请输入你要发送的信息>>>>>").strip()

    # 判断发送的内容是否为空
    if len(cmd) == 0:
        continue

    # 将信息打包发送给服务端
    client.send(cmd.encode("utf8"))

    # 接收到服务端回馈的信息
    k_date = client.recv(1024)

    # 打印服务短的消息
    print(f"这是服务端发来的消息{k_date.decode('utf8')}")

# 结束服务
client.close()

"""可以有多个客户端与服务端建立连接 """