• 进程池,线程池&协程


    线程池与进程池

      池是一个容器的概念,所谓进程池,线程池,就是建立好的进程或线程,在一个容器对象中,且可以重复使用。开启进程与线程都需要消耗资源,两者相比,线程消耗资源更少一些。但是为了能在计算机硬件承受范围内最大限度地利用计算机资源,可以使用线程池与进程池。同时进程池线程池限制了程序云效率,但是保证了计算机安全。

      创建线程池与线程池都在concurrent.future模块下ThreadPoolExeutor(线程池),ProcessPoolExecutor(进程池)。首先需要进线程池创建对象,开启进线程时需要用到submit()方法,且都有返回结果,结果对象需要用到result()获取结果。进线程对象都有shutdown()方法关闭对象。

    '''
    线程池
        两种方式
    '''
    import time
    from concurrent.futures import ThreadPoolExecutor   # 调用线程池
    
    pool = ThreadPoolExecutor(5)     # 创建线程池对象 线程创建个数默认是当前计算cup个数乘以5,现在设定5个
    
    def func(n):
        print(f'{n}来了')
        time.sleep(2)
        return f'{n}走了'
    
    t_list = []
    for i in range(20):   # 开启20个线程
        res = pool.submit(func, f'{i}号伞兵')  # 开启线程, 获取结果对象
        t_list.append(res)  # 添加到列表中
    for k in t_list:
        print(k.result())  # 打印结果
    '''
    线程池处理的第二种方式
    '''
    import time
    from concurrent.futures import ThreadPoolExecutor
    # 调用线程池
    
    pool = ThreadPoolExecutor(5)     # 创建线程池对象
    
    def func(n):
        print(f'{n}来了')
        time.sleep(2)
        return f'{n}走了'
    
    def call_back(m):  # 返回结果处理函数
        print(m.result())
    
    
    for i in range(20):
        pool.submit(func, f'{i}号伞兵').add_done_callback(call_back)   # 使用add_done_callback设置返回结果处理
    '''
    进程池两种方式
    '''
    import time
    from concurrent.futures import ProcessPoolExecutor
    # 调用进程池
    
    pool = ProcessPoolExecutor(5)     # 创建进程池 默认是cup个数
    
    def func(n):
        print(f'{n}来了')
        time.sleep(2)
        return f'{n}走了'
    
    if __name__ == '__main__':
        t = []
        for i in range(20):
            res = pool.submit(func, f'{i}号伞兵')
            t.append(res)
        for k in t:
            print(k.result())
        pool.shutdown()
    '''
    创建进程第二种方式
    '''
    import time
    from concurrent.futures import ProcessPoolExecutor
    # 调用进程池
    
    pool = ProcessPoolExecutor(5)     # 创建进程池 默认是cup个数
    
    def func(n):
        print(f'{n}来了')
        time.sleep(2)
        return f'{n}走了'
    
    def call_back(m):
        print(m.result())
    
    if __name__ == '__main__':
        for i in range(20):
            pool.submit(func, f'{i}号伞兵').add_done_callback(call_back)
    进线程对象

    协程

      协程是程序员自定义一名词,是对单线程下实现并发,称之为协程。并发是一种现象:是主观上看起来计算机同时执行多个任务。实现并发计算的多道技术就是并发的一种体现,当进程遇到I/O操作时计算机便会保存当前状态,切换到下一个事件的计算。因此要做到切换和保存状态边可以实现并发。在python中使用genvent包中spawn和mokey模块,可以做到保存状态加切换。

    import time
    from gevent import spawn, monkey;monkey.patch_all()  # monkey.patch_all() 检测I/O
    
    def func1():
        print(111)
        time.sleep(1)   # 模拟I/O阻塞
        print(111)
    
    def func2():
        print(222)
        time.sleep(2)
        print(222)
    
    spawn(func1)      # spawn模块会检测函数中的I/O,检测到I/O状态,就会调到其他非阻塞
    res = spawn(func2)  # 检测func2
    res.join()   # 等待

    利用协程实现单核下TCP并发通信

    '''
    服务端
    '''
    import socket
    from gevent import spawn, monkey
    monkey.patch_all()
    
    server = socket.socket()
    server.bind(('127.0.0.1', 8081))
    server.listen(5)
    
    def talk(conn):
        while True:
            try:
                data = conn.recv(1024)
                if len(data) == 0: break
                print(data.decode('utf-8'))
                conn.send(data.upper())
            except BaseException as e:
                print(e)
                break
        conn.close()
    
    def server1():
        while True:
            conn, addr = server.accept()
            spawn(talk, conn)   # 检测talk函数,传入conn参数
    
    if __name__ == '__main__':
        res = spawn(server1)  # 检测阻塞态
        res.join()
    '''
    服务端
    '''
    import socket
    from threading import Thread,current_thread
    
    
    def clint1():
        clint = socket.socket()
        clint.connect(('127.0.0.1', 8081))
        i = 0
        while True:
            msg = '%s--%s' % (current_thread().name, i)
            clint.send(msg.encode('utf-8'))
            data = clint.recv(1024)
            print(data.decode('utf-8'))
            i += 1
    
    for i in range(400):   # 开启400个线程,访问服务端
        t = Thread(target=clint1)
        print(current_thread().name)
        t.start()

      写成应用应根据任务不同来使用,对于计算密集型的任务来说,不适合用协程,但对于I/O密集型协程是适合的。

      对于并发:可以开多进程,多进程下开多线程,多线程下还可以开多协程!!!

  • 相关阅读:
    我的第一个博客在博客园安家了,哈哈~欢迎大家光临
    JS未设置对象问题解决方案
    关于Oracle的优化
    USACO 1.2 Milking Cows
    C语言的文件操作 freopen
    USACO 1.2 Palindromic Squares
    USACO 1.1 Broken Necklace
    ACM征程再次起航!
    USACO 1.3 Barn Repair
    USACO 1.2 Transformations
  • 原文地址:https://www.cnblogs.com/huaiXin/p/11358826.html
Copyright © 2020-2023  润新知