# 为什么要有进程池?
# 因为开启过多的进程并不能提高程序的运行效率,反而会降低效率
#
# 任务的分类:计算密集型、IO密集型
# 计算密集型:充分占用CPU, 多进程可以充分利用多核
# IO密集型: 大部分时间都在阻塞,而不是在运行状态中,根本不适合开启多进程

# 500个任务
# 5 个进程

# 信号量机制(semaphore):   多进程共享有限的资源
      # 500件衣服    任务
      # 500个人      进程
      # 只有4台机器  CPU

# 多进程机制:多个进程并行或并发执行行,竞争资源,大量进程的创建 和销毁 ,将占用大量系统开销
    # 500件衣服  任务
    # 500个人   进程
    # 抢4台机器


# 进程池机制(Process Pool):循环使用进程池中的进程来执行任务,可以对空闲进程进行利用,节省创建和销毁进程的开销。
    # 500 件衣服  任务
    # 500 个人   进程
    # 4 台机器



import time
from multiprocessing import Pool,Process

# def func(num):    # 定义一个函数,用来执行做衣服的任务
#     print("做了第%s件脱衣服" % num)
#
#
# if __name__ == '__main__':
#     time_start = time.time()  # 如果要进行时间的计算,优先获得时间戮格式
#     pool = Pool(4)  # 实例化一个进程池对象
#     for i in range(100):
#         pool.apply_async(func,args=(i,))  # 异步提交一个func到子进程中执行
#     pool.close()  # 关闭进程池,用户不能再向这个池中提交任务了
#     pool.join()   # 阻塞,直到提交到进程池中的所有任务执行结束
#     time_stop = time.time()
#     interval = time_stop - time_start
#     print(interval)   # 0.3530256748199463  通过进程池,来跑100个进程,耗时明显短很多,相对于多进程方式
#
#
# if __name__ == "__main__":
#     time_start = time.time()
#     p_list = list()
#     for i in range(100):
#         p = Process(target=func,args=(i,))
#         p.start()
#         p_list.append(p)
#     for p in p_list:p.join()   # 主进程 和 子进程虽然是并发执行的,但我在主进程中调用此方法,判断全部子进程
#     # 运行结束,主进程再往下继续执行
#     print(time.time() - time_start) # 5.312794208526611  耗时较多

    # 提交任务的方法: 有同步提交  与 异步提交
    # 同步提交:指的是提交的子进程之间是顺序执行的
    # 异步提交:指的是提交的子进程是并发执行的
import os
# def task(num):
#     time.sleep(1)
#     print("%s : %s"  % (num,os.getpid()))
#     return num**2
#
# if __name__ == '__main__':
#     p = Pool()
#     for i in range(20):
#         res = p.apply(task,args=(i,))  # 提交任务的方法,同步提交  即子进程是顺序执行的,相当于加了p.join()
#         print("--->",res)



# def task(num):
#     time.sleep(1)
#     print("%s : %s" % (num,os.getpid()))
#     return num**2
#
# if __name__ == '__main__':
#     print(os.cpu_count())
#     p = Pool()   # 如是不传参的话,进程池,进程数了为CPU的核心的数量
#     for i in range(20):
#         p.apply_async(task,args=(i,))  # 提交任务的方法,异步提交
#     p.close()
#     p.join()


# def task(num):
#     time.sleep(1)
#     print("%s : %s" % (num,os.getpid()))
#     return num**2
#
# if __name__ == '__main__':
#     p = Pool()
#     res_list = list()
#     for i in range(20):
#         res = p.apply_async(task,args=(i,))
#         # print(res)  # <multiprocessing.pool.ApplyResult object at 0x0000019FD66D43C8>
#         res_list.append(res)
#     for res in res_list:print(res.get())  # 在有返回值的情况下,res.get() ,不能在提交任务之后,立刻
    # 执行,应该是先提交所有的任务,再通过 res.get()获取结果
#
# def task(num):
#     time.sleep(1)
#     print("%s : %s" % (num,os.getpid()))
#     return num**2
#
# if __name__ == '__main__':
#     p = Pool()
#     res_list = list()
#     for i in range(20):
#         res = p.apply_async(task,args=(i,))
#         print(res.get())   # rss.get()没有取到结果,会阻塞,就变成了顺序执行了

def task(args):
    time.sleep(2)
    num,n = args
    num,n = args
    print(f"{num},{n} : {os.getpid()}")
    return num**2

if __name__ == '__main__':
    p = Pool()
    p.map(task,((1,3),))


# 实例化 传参数   进程的个数 cpus
# # 提交任务:
# 同步提交  apply
    # 返回值: 子进程 对应函数的返回值
    # 一个一个顺序执行的,并没有任何并发效果
# 异步提交 apply_async
    # 没有返回值,要想所有任务能够顺利的执行完毕
      # p.close()
      # p.join()  必须先close再join,阻塞直到提交到进程池中的所有任务都执行完毕。
    # 有返回值的情况下
      # res.get() # get不能在提交任务之后,立刻执行,应该是先提交所有的任务,然后再通过get()获取结果
      
      # map()方法
        # 异步提交的简化版本
        # 自带close 和 join 方法