网络编程二:并发、多进程、多进程间的通信

一、并发

操作系统同时运行多个任务。

单核CPU实现多任务的原理:操作系统轮流让各个任务交替执行---QQ执行2us,切换到微信执行2us,再切换到陌陌执行2us............实际上是每个任务在轮流反复执行,但是因为cpu调度执行速度太快了,导致我们感觉所有任务都在同时运行。

多核CPU实现多任务原理:如果任务数量小于CPU数量,那是真正的多任务并行执行;但是实际上操作系统的任务远远多于CPU核数;多出CPU数量的任务实际上,也是轮流调度到每个CPU核心上执行。

并发:看上去一起执行,任务数量多于CPU核心数量

并行:真正一起执行,任务数量小于等于CPU核心数量

实现多任务的方式:

  • 多进程模式
  • 多线程模式
  • 协程模型
  • 多进程+多线程模型

二、多进程

对于操作系统而言,一个任务就是一个进程。

进程是操作系统中,程序执行和资源分配的基本单位。

每个进程都有自己的数据段、代码段、堆栈。

多进程库:multiprocessing,跨平台

在linux系统,也可以使用fork多进程。

import time, os, multiprocessing
def run():
    print("子进程启动--", os.getpid())
    time.sleep(3)
    print("子进程结束--", os.getpid())
if __name__ == '__main__':
    print("父进程启动--", os.getpid())
    p = multiprocessing.Process(target=run)
    p.start()
    # 父进程的结束,不会也不能影响子进程的结束
    print("父进程结束--", os.getpid())
父进程启动-- 8752
父进程结束-- 8752
子进程启动-- 7532
子进程结束-- 7532

通常情况下,我们需要父进程,等待子进程结束后,才能结束父进程;此时,对子进程p调用join()方法,即可

if __name__ == '__main__':
    print("父进程启动--", os.getpid())
    p = multiprocessing.Process(target=run)
    p.start()
 p.join()
# 父进程将等待子进程结束后,才会结束 print("父进程结束--", os.getpid())
父进程启动-- 8720
子进程启动-- 9032
子进程结束-- 9032
父进程结束-- 8720

 全局变量,不能在多个进程中共享

import os, multiprocessing
num = 100
def run():
    print("子进程启动--", os.getpid())
    global num
    num += 1
    print("子进程中的num: ", num)
    print("子进程结束--", os.getpid())
if __name__ == '__main__':
    print("父进程启动--", os.getpid())
    p = multiprocessing.Process(target=run)
    p.start()
    p.join()
    # 全局变量在多个进程中,不能共享
    # 在子程中,修改全局变量,对父进程中的全局变量没有影响
    # 因为,在创建子进程时,对全局变量做了一个备份;父进程中的num与子进程中的num是两个完全不同的变量
    print("父进程中的num: ", num)
    # 进程之间的变量也是不共享的
    p = multiprocessing.Process(target=run)
    p.start()
    p.join()
    print("父进程结束--%s" % os.getpid())
父进程启动-- 9772
子进程启动-- 9292
子进程中的num:  101
子进程结束-- 9292
父进程中的num:  100
子进程启动-- 9572
子进程中的num:  101
子进程结束-- 9572
父进程结束--9772

 

多进程:这里使用进程池创建多个进程

import time, os, multiprocessing, random
def run(name):
    print("子进程{}启动--".format(name), os.getpid())
    start = time.time()
    time.sleep(random.choice([1, 2, 3]))
    end = time.time()
    print("子进程{}结束{}--耗时{}".format(name, os.getpid(), end-start))
if __name__ == '__main__':
    print("父进程启动--", os.getpid())
    # Pool,默认的进程池大小为CPU核心数,这里为2
    pool = multiprocessing.Pool()
    for i in range(3):
        # 创建进程,放入进程池统一管理
        pool.apply_async(run, args=(i,))
    # close()方法:调用此方法后,则不能再向进程池添加进程;
    # close()方法必须在join()方法之前调用
    pool.close()
    # join方法:让父进程,等待子进程结束后,再结束
    # pool.join方法:让父进程,等待进程池中所有子进程结束后,再结束
    pool.join()
    print("父进程结束--%s" % os.getpid())

在进程池中,先启动哪个子进程,是没有先后顺序的。

三、进程间的通信

1.使用Queue实现进程间的通信:multiprocessing.Queue

由父进程创建队列,并传递给子进程;接收到队列的子进程,可以共享此队列。

from multiprocessing import Process, Queue
import os,time
def write(q):
    print("启动写子进程,", os.getpid())
    for chr in ["A", "B", "C", "D"]:
        q.put(chr)
        time.sleep(1)
    print("结束写子进程,", os.getpid())
def read(q):
    print("启动读子进程,", os.getpid())
    while True:
        value = q.get(True)
        print("value = ", value)
    print("结束读子进程,", os.getpid())
if __name__ == '__main__':
    print("启动父进程,", os.getpid())
    # 父进程创建队列,传递给子进程使用
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    pw.start()
    pr.start()
    pw.join()
    # pr进程是一个死循环,无法等待其结束;只能强行结束
    pr.terminate()
    print("结束父进程,", os.getpid())

 

posted on 2018-10-28 11:13  myworldworld  阅读(162)  评论(0)    收藏  举报

导航