【11.0】进程池和线程池

【一】TCP实现并发的效果的原理

  • 每开设一个客户端,就会有一个服务端服务

【1】服务端

from socket import *
from threading import Thread


def server_create(IP, PORT):
    server = socket()

    server.bind((IP, PORT))

    server.listen(5)

    while True:
        conn, addr = server.accept()
        t = Thread(target=conn_communication, args=(conn,))


def conn_communication(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:
                break
            print(data.decode('utf8'))
            conn.send(data.upper())
        except Exception as e:
            print(e)
            break
    conn.close()


def main():
    IP = '127.0.0.1'
    PORT = 8086
    t = Thread(target=server_create, args=(IP, PORT,))
    t.start()


if __name__ == '__main__':
    main()

【2】客户端

from socket import *


def client_create(IP, PORT):
    client = socket()

    client.connect((IP, PORT))

    while True:
        word = b'hello world'
        client.send(word)

        msg = client.recv(1024)
        print(msg)


if __name__ == '__main__':
    IP = '127.0.0.1'
    PORT = 8086

    client_create(IP, PORT)

【3】小结

  • 无论是开设进程还是开设线程,都需要消耗资源
  • 只不过开始线程消耗的资源比开始进程相对少一些
  • 硬件的开发速度永远赶不上软件开发速度
  • 我们的宗旨是保证计算机硬件正常工作的情况下最大程度的利用它

【二】什么是池

  • 池是用来保证计算机硬件安全的情况下最大限度的利用计算机
  • 池降低了程序的运行效率,但是保证了计算机硬件的安全,从而保证程序的正常运行

【三】线程池

【1】语法

from concurrent.futures import ThreadPoolExecutor

# 默认开设当前计算机 cpu 个数五倍数的线程数
# 可以指定线程总数
pool = ThreadPoolExecutor(5)

【2】原理

  • 池子造出来后 里面固定存在五个线程
  • 这五个线程不会存在出现重复创建和销毁的过程

【3】优点

  • 避免了重复创建五个线程的资源开销

【4】使用方法

(0)任务的提交方式

  • 同步:提交任务之后原地等待任务的返回结果,期间不做任何事
  • 异步:提交任务之后不等待任务的返回结果,继续执行代码
    • 思考:返回结果如何获取?

(1)同步提交

from concurrent.futures import ThreadPoolExecutor
import time

# 构造线程池,指定线程总数
pool = ThreadPoolExecutor(5)


# 定义线程任务
def task(n):
    print(n)
    time.sleep(2)


# 向线程池中添加线程任务
def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task')

    # 1
    # this is a main task


if __name__ == '__main__':
    normal()

(2)异步提交

from concurrent.futures import ThreadPoolExecutor
import time

# 构造线程池,指定线程总数
pool = ThreadPoolExecutor(5)


# 定义线程任务
def task(n):
    print(n)
    time.sleep(2)


# 向线程池中添加线程任务
def normal():
    pool.submit(task, 1)

    # 异步提交 - 先执行子线程再打印主线程
    print('this is a main task')

    # 1
    # this is a main task


def many_steps():
    for i in range(20):
        pool.submit(task, i)
    print('this is a main task')


if __name__ == '__main__':
    many_steps()

    # 0
    # 1
    # 2
    # 3
    # 4
    # this is a main task
    # 先执行五个子线程,再回到主线程
    # 5
    # 6
    # 7
    # 8
    # 9
    # 10
    # 11
    # 12
    # 13
    # 14
    # 15
    # 16
    # 17
    # 18
    # 19

【5】异步返回值

(1)查看异步回调对象

from concurrent.futures import ThreadPoolExecutor
import time

# 构造线程池,指定线程总数
pool = ThreadPoolExecutor(5)


# 定义线程任务
def task(n):
    print(f"这是线程任务中的 n :>>>> {n}")
    time.sleep(2)
    return n * 2


def many_steps():
    for i in range(5):
        # 提交任务到线程池,并获取到返回值
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        # <Future at 0x134d3fcd0 state=pending>
        print(f'这是 pool的返回值:>>>>{res.result()}')  # None
        # 程序由并发变成了串行
        # 返回的结果是 None ---> 任务的返回结果 ----> 拿到了异步提交的返回结果
        # res.result() : 拿到的就是异步提交的任务的返回结果
    print('this is a main task')
    # 这是线程任务中的 n :>>>> 0这是 pool的返回值:>>>><Future at 0x104f36350 state=running>
    #
    # 这是 pool的返回值:>>>>0
    # 这是 pool的返回值:>>>><Future at 0x11747b460 state=pending>
    # 这是线程任务中的 n :>>>> 1
    # 这是 pool的返回值:>>>>2
    # 这是 pool的返回值:>>>><Future at 0x104f36350 state=pending>
    # 这是线程任务中的 n :>>>> 2
    # 这是 pool的返回值:>>>>4
    # 这是 pool的返回值:>>>><Future at 0x11747b160 state=pending>
    # 这是线程任务中的 n :>>>> 3
    # 这是 pool的返回值:>>>>6
    # 这是 pool的返回值:>>>><Future at 0x104f36350 state=pending>
    # 这是线程任务中的 n :>>>> 4
    # 这是 pool的返回值:>>>>8
    # this is a main task


if __name__ == '__main__':
    many_steps()

(2)调用异步回调对象

from concurrent.futures import ThreadPoolExecutor
import time

# 构造线程池,指定线程总数
pool = ThreadPoolExecutor(5)


# 定义线程任务
def task(n):
    print(f"这是线程任务中的 n :>>>> {n}")
    time.sleep(2)
    return n * 2


def many_steps():
    task_list = []
    for i in range(5):
        # 提交任务到线程池,并获取到返回值
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        # <Future at 0x134d3fcd0 state=pending>
        task_list.append(res)

    for task_every in task_list:
        print(f'这是 pool的返回值:>>>>{task_every.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的
    print('this is a main task')
    # 这是线程任务中的 n :>>>> 0这是 pool的返回值:>>>><Future at 0x154e6bfa0 state=running>
    # 
    # 这是线程任务中的 n :>>>> 1
    # 这是 pool的返回值:>>>><Future at 0x15511bc10 state=running>
    # 这是线程任务中的 n :>>>> 2这是 pool的返回值:>>>><Future at 0x15511beb0 state=running>
    # 
    # 这是线程任务中的 n :>>>> 3
    # 这是 pool的返回值:>>>><Future at 0x1551401c0 state=running>
    # 这是线程任务中的 n :>>>> 4
    # 这是 pool的返回值:>>>><Future at 0x1551404c0 state=running>
    # 这是 pool的返回值:>>>>0
    # 这是 pool的返回值:>>>>2
    # 这是 pool的返回值:>>>>4
    # 这是 pool的返回值:>>>>6
    # 这是 pool的返回值:>>>>8
    # this is a main task


if __name__ == '__main__':
    many_steps()

【6】pool.shutdown()

  • 等待所有子线程结束后再打印程序运行结果
from concurrent.futures import ThreadPoolExecutor
import time

# 构造线程池,指定线程总数
pool = ThreadPoolExecutor(5)


# 定义线程任务
def task(n):
    print(f"这是线程任务中的 n :>>>> {n}")
    time.sleep(2)
    return n * 2


def many_steps():
    task_list = []
    for i in range(5):
        # 提交任务到线程池,并获取到返回值
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        # <Future at 0x134d3fcd0 state=pending>
        task_list.append(res)

    # 关闭线程池 - 等待所有的线程池中的任务运行完毕
    pool.shutdown()

    for task_every in task_list:
        print(f'这是 pool的返回值:>>>>{task_every.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的
    print('this is a main task')
    # 这是线程任务中的 n :>>>> 0
    # 这是 pool的返回值:>>>><Future at 0x13a713fa0 state=running>
    # 这是线程任务中的 n :>>>> 1
    # 这是 pool的返回值:>>>><Future at 0x13a9c3c70 state=running>
    # 这是线程任务中的 n :>>>> 2
    # 这是 pool的返回值:>>>><Future at 0x13a9c3f10 state=running>
    # 这是线程任务中的 n :>>>> 3
    # 这是 pool的返回值:>>>><Future at 0x13a9ec220 state=running>
    # 这是线程任务中的 n :>>>> 4
    # 这是 pool的返回值:>>>><Future at 0x13a9ec520 state=running>
    # 这是 pool的返回值:>>>>0
    # 这是 pool的返回值:>>>>2
    # 这是 pool的返回值:>>>>4
    # 这是 pool的返回值:>>>>6
    # 这是 pool的返回值:>>>>8
    # this is a main task


if __name__ == '__main__':
    many_steps()

【四】进程池的使用

  • 开设进程的进程 ID 号不会发生改变
import os
from concurrent.futures import ProcessPoolExecutor
import time

# 构造进程池,指定进程总数
pool = ProcessPoolExecutor(5)


# 定义线程任务
def task(n):
    print(n, f'当前进程的进程号:>>>{os.getpid()}')
    print(f"这是线程任务中的 n :>>>> {n}")
    time.sleep(2)
    return n * 2


def many_steps():
    task_list = []
    for i in range(5):
        # 提交任务到进程池,并获取到返回值
        res = pool.submit(task, i)
        print(f'这是 pool的返回值:>>>>{res}')
        # 返回值是一个类对象 - result 方法 ----> 返回异步回调的结果
        # <Future at 0x134d3fcd0 state=pending>
        task_list.append(res)

    # 关闭进程池 - 等待所有的进程池中的任务运行完毕
    pool.shutdown()

    for task_every in task_list:
        print(f'这是 pool的返回值:>>>>{task_every.result()}')  # None
        # 程序由变成了串行
        # res.result() : 拿到的就是异步提交的任务的返回结果
        # 程序运行的结果是有序的
        
    print('this is a main task')
    # 这是 pool的返回值:>>>><Future at 0x136434a30 state=running>
    # 这是 pool的返回值:>>>><Future at 0x136435630 state=running>
    # 这是 pool的返回值:>>>><Future at 0x136435810 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x136435bd0 state=pending>
    # 这是 pool的返回值:>>>><Future at 0x136435ba0 state=pending>
    # 0 当前进程的进程号:>>>44758
    # 这是线程任务中的 n :>>>> 0
    # 1 当前进程的进程号:>>>44759
    # 这是线程任务中的 n :>>>> 1
    # 2 当前进程的进程号:>>>44756
    # 这是线程任务中的 n :>>>> 2
    # 3 当前进程的进程号:>>>44757
    # 这是线程任务中的 n :>>>> 3
    # 4 当前进程的进程号:>>>44760
    # 这是线程任务中的 n :>>>> 4
    # 这是 pool的返回值:>>>>0
    # 这是 pool的返回值:>>>>2
    # 这是 pool的返回值:>>>>4
    # 这是 pool的返回值:>>>>6
    # 这是 pool的返回值:>>>>8
    # this is a main task


if __name__ == '__main__':
    many_steps()

【五】异步回调函数

  • add_done_callback(call_back)

  • add_done_callback(call_back) 返回值正是我们的上面 pool的返回的结果

import os
from concurrent.futures import ProcessPoolExecutor
import time

# 构造进程池,指定进程总数
pool = ProcessPoolExecutor(5)


# 定义线程任务
def task(n):
    print(n, f'当前进程的进程号:>>>{os.getpid()}')
    print(f"这是线程任务中的 n :>>>> {n}")
    time.sleep(2)
    return n * 2


# 定义一个异步回调函数
def call_back(n):
    print(f'call_back>>>:{n}')


def many_steps():
    task_list = []
    for i in range(5):
        # 提交任务到进程池,并获取到返回值,添加一个异步回调函数
        res = pool.submit(task, i).add_done_callback(call_back)
        print(f'这是 pool的返回值:>>>>{res}')
        
    print('this is a main task')
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # this is a main task
    # 0 当前进程的进程号:>>>44878
    # 这是线程任务中的 n :>>>> 0
    # 1 当前进程的进程号:>>>44875
    # 这是线程任务中的 n :>>>> 1
    # 2 当前进程的进程号:>>>44876
    # 这是线程任务中的 n :>>>> 2
    # 3 当前进程的进程号:>>>44879
    # 这是线程任务中的 n :>>>> 3
    # 4 当前进程的进程号:>>>44877
    # 这是线程任务中的 n :>>>> 4
    # call_back>>>:<Future at 0x12ca38910 state=finished returned int>
    # call_back>>>:<Future at 0x12ca392d0 state=finished returned int>
    # call_back>>>:<Future at 0x12ca39870 state=finished returned int>
    # call_back>>>:<Future at 0x12ca39780 state=finished returned int>
    # call_back>>>:<Future at 0x12ca39cf0 state=finished returned int>


if __name__ == '__main__':
    many_steps()

【3】查看异步回调结果

import os
from concurrent.futures import ProcessPoolExecutor
import time

# 构造进程池,指定进程总数
pool = ProcessPoolExecutor(5)


# 定义线程任务
def task(n):
    print(n, f'当前进程的进程号:>>>{os.getpid()}')
    print(f"这是线程任务中的 n :>>>> {n}")
    time.sleep(2)
    return n * 2


# 定义一个异步回调函数
def call_back(n):
    print(f'call_back>>>:{n} | 返回的结果为:>>>{n.result()}')


def many_steps():
    task_list = []
    for i in range(5):
        # 提交任务到进程池,并获取到返回值,添加一个异步回调函数
        res = pool.submit(task, i).add_done_callback(call_back)
        print(f'这是 pool的返回值:>>>>{res}')

    print('this is a main task')
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # 这是 pool的返回值:>>>>None
    # this is a main task
    # 0 当前进程的进程号:>>>45050
    # 这是线程任务中的 n :>>>> 0
    # 1 当前进程的进程号:>>>45049
    # 这是线程任务中的 n :>>>> 1
    # 2 当前进程的进程号:>>>45046
    # 这是线程任务中的 n :>>>> 2
    # 3 当前进程的进程号:>>>45047
    # 这是线程任务中的 n :>>>> 3
    # 4 当前进程的进程号:>>>45048
    # 这是线程任务中的 n :>>>> 4
    # call_back>>>:<Future at 0x122038910 state=finished returned int> | 返回的结果为:>>>0
    # call_back>>>:<Future at 0x122039510 state=finished returned int> | 返回的结果为:>>>2
    # call_back>>>:<Future at 0x122039840 state=finished returned int> | 返回的结果为:>>>4
    # call_back>>>:<Future at 0x122039ab0 state=finished returned int> | 返回的结果为:>>>6
    # call_back>>>:<Future at 0x122039cf0 state=finished returned int> | 返回的结果为:>>>8


if __name__ == '__main__':
    many_steps()

【五】总结

【1】进程池模版

# 导入模块
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# 构建线程池或进程池
pool_process = ProcessPoolExecutor(5)


# 构造异步任务
def task(n):
    print(f'这是异步传进来的参数 n :>>>> {n}')
    return n ** 2


def main_process():
    task_result_list = []
    for i in range(5):
        # 提交任务
        result = pool_process.submit(task, i)
        print(f'这是异步 {i} 调用的返回结果 :>>>> {result}')
        # 提交线程任务结果
        task_result_list.append(result)

    #  关闭进程池,等待进程池中所有的任务完成
    pool_process.shutdown()

    # 逐个获取到异步迭代的结果
    for task_every in task_result_list:
        print(f'这是异步调用的返回结果 :>>>> {task_every.result()}')


if __name__ == '__main__':
    main_process()

    # 这是异步 0 调用的返回结果 :>>>> <Future at 0x110e59030 state=running>
    # 这是异步 1 调用的返回结果 :>>>> <Future at 0x110e59c60 state=running>
    # 这是异步 2 调用的返回结果 :>>>> <Future at 0x110e59a20 state=running>
    # 这是异步 3 调用的返回结果 :>>>> <Future at 0x110e5a140 state=pending>
    # 这是异步 4 调用的返回结果 :>>>> <Future at 0x110e5a3e0 state=pending>
    # 这是异步传进来的参数 n :>>>> 0
    # 这是异步传进来的参数 n :>>>> 1
    # 这是异步传进来的参数 n :>>>> 2
    # 这是异步传进来的参数 n :>>>> 3
    # 这是异步传进来的参数 n :>>>> 4
    # 这是异步调用的返回结果 :>>>> 0
    # 这是异步调用的返回结果 :>>>> 1
    # 这是异步调用的返回结果 :>>>> 4
    # 这是异步调用的返回结果 :>>>> 9
    # 这是异步调用的返回结果 :>>>> 16

【2】线程池模版

# 导入模块
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# 构建线程池或进程池
pool_thread = ThreadPoolExecutor(5)


# 构造异步任务
def task(n):
    print(f'这是异步传进来的参数 n :>>>> {n}')
    return n ** 2

def main_thread():
    task_result_list = []
    for i in range(5):
        # 提交任务
        result = pool_thread.submit(task, i)
        print(f'这是异步 {i} 调用的返回结果 :>>>> {result}')
        task_result_list.append(result)

    #  关闭进程池,等待进程池中所有的任务完成
    pool_process.shutdown()

    # 逐个获取到异步迭代的结果
    for task_every in task_result_list:
        print(f'这是异步调用的返回结果 :>>>> {task_every.result()}')


if __name__ == '__main__':

    main_thread()

    # 这是异步传进来的参数 n :>>>> 0
    # 这是异步 0 调用的返回结果 :>>>> <Future at 0x12e30ead0 state=finished returned int>
    # 这是异步 1 调用的返回结果 :>>>> <Future at 0x12e30f190 state=pending>
    # 这是异步传进来的参数 n :>>>> 1
    # 这是异步 2 调用的返回结果 :>>>> <Future at 0x12e30f790 state=pending>
    # 这是异步传进来的参数 n :>>>> 2
    # 这是异步传进来的参数 n :>>>> 3
    # 这是异步 3 调用的返回结果 :>>>> <Future at 0x12e33a3e0 state=finished returned int>
    # 这是异步 4 调用的返回结果 :>>>> <Future at 0x12e30f4c0 state=pending>
    # 这是异步调用的返回结果 :>>>> 0
    # 这是异步调用的返回结果 :>>>> 1
    # 这是异步调用的返回结果 :>>>> 4
    # 这是异步调用的返回结果 :>>>> 9
    # 这是异步传进来的参数 n :>>>> 4
    # 这是异步调用的返回结果 :>>>> 16

【3】回调函数模版

# 导入模块
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# 构建线程池或进程池
pool_process = ProcessPoolExecutor(5)
pool_thread = ThreadPoolExecutor(5)


# 构造异步任务
def task(n):
    print(f'这是异步传进来的参数 n :>>>> {n}')
    return n ** 2


# 构造异步调用函数
def call_back(n):
    print(f'这是异步调用函数中接收到的 :>>>> {n.result()}')
    return n.result() ** 2


def main_process():
    for i in range(5):
        # 提交任务
        result_call_back = pool_process.submit(task, i).add_done_callback(call_back)
        print(f'这是异步 {i} 调用的返回结果 :>>>> {result_call_back}')


def main_thread():
    for i in range(5):
        # 提交任务
        result_call_back = pool_thread.submit(task, i).add_done_callback(call_back)
        print(f'这是异步 {i} 调用的返回结果 :>>>> {result_call_back}')


if __name__ == '__main__':
    main_process()

    # 这是异步 0 调用的返回结果 :>>>> None
    # 这是异步 1 调用的返回结果 :>>>> None
    # 这是异步 2 调用的返回结果 :>>>> None
    # 这是异步 3 调用的返回结果 :>>>> None
    # 这是异步 4 调用的返回结果 :>>>> None
    # 这是异步传进来的参数 n :>>>> 0
    # 这是异步传进来的参数 n :>>>> 1
    # 这是异步传进来的参数 n :>>>> 2
    # 这是异步传进来的参数 n :>>>> 3
    # 这是异步传进来的参数 n :>>>> 4
    # 这是异步调用函数中接收到的 :>>>> 0
    # 这是异步调用函数中接收到的 :>>>> 1
    # 这是异步调用函数中接收到的 :>>>> 4
    # 这是异步调用函数中接收到的 :>>>> 9
    # 这是异步调用函数中接收到的 :>>>> 16

    # main_thread()

    # 这是异步传进来的参数 n :>>>> 0
    # 这是异步调用函数中接收到的 :>>>> 0
    # 这是异步 0 调用的返回结果 :>>>> None
    # 这是异步 1 调用的返回结果 :>>>> None
    # 这是异步传进来的参数 n :>>>> 1
    # 这是异步调用函数中接收到的 :>>>> 1
    # 这是异步 2 调用的返回结果 :>>>> None
    # 这是异步传进来的参数 n :>>>> 2
    # 这是异步传进来的参数 n :>>>> 3
    # 这是异步调用函数中接收到的 :>>>> 9
    # 这是异步 3 调用的返回结果 :>>>> None
    # 这是异步调用函数中接收到的 :>>>> 4
    # 这是异步 4 调用的返回结果 :>>>> None
    # 这是异步传进来的参数 n :>>>> 4
    # 这是异步调用函数中接收到的 :>>>> 16
posted @ 2024-01-23 14:29  Chimengmeng  阅读(16)  评论(0编辑  收藏  举报