python多线程与多进程理解

1、线程与进程
进程:一个程序的执行实例就是一个进程,每一个进程提供执行程序所需的所有资 源。(进程本质上是资源的集合),操作系统管理在其上面运行的所有进程,并为这些进程公平的分配时间。
线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。


2、单线程

from time import ctime,sleep

def music(func):
    for i in range(2):
        print ("I was listening to %s. %s" %(func,ctime()))
        sleep(1)

def movie(func):
    for i in range(2):
        print ("I was at the %s! %s" %(func,ctime()))
        sleep(5)

if __name__ == '__main__':
    music(u'爱情买卖')
    movie(u'阿凡达')
    print ("all over %s" %ctime())

一个任务只能等待上一个任务完成,才能执行。是阻塞的。

3、多线程
Python的标准库提供了两个模块:_threadthreading_thread是低级模块,它不支持守护线程,当主线程退出时,所有子线程都会被强行退出。threading是高级模块,对_thread进行了封装,支持守护线程,绝大多数情况下,我们只需要使用threading这个高级模块。

import threading
from time import ctime,sleep


def music(func,loop):
    for i in range(loop):
        print ("I was listening to %s. %s" %(func,ctime()))
        sleep(1)

def movie(func,loop):
    for i in range(loop):
        print ("I was at the %s! %s" %(func,ctime()))
        sleep(5)
#创建线程组
threads = []
#创建线程t1,添加到线程组,目标函数,以及传参
t1 = threading.Thread(target=music,args=('爱情买卖',2))
threads.append(t1)
#创建线程t1,添加到线程组
t2 = threading.Thread(target=movie,args=('阿凡达',3))
threads.append(t2)

if __name__ == '__main__':
    #启动线程
    for t in threads:
        t.start()
    #守护线程
    for t in threads:
    # join()的作用是,等待每个线程终止。
        t.join()
    print ("all over %s" %ctime())

这里写图片描述

3、多进程
多进程multiprocessing模块提供远程与本地的并发,在一个multiprocessing库的典型使用场景下,所有的子进程都是由一个父进程启动起来的,这个父进程成为madter进程,这个父进程非常重要,他会管理一系列的对象状态,一旦这个进程退出,子进程很可能处于一个不稳定的状态,这个进程最好尽可能做最少的事情,以便保持其稳定性。


Process([group [, target [, name [, args [, kwargs]]]]])

  • group分组,实际上不使用
  • target表示调用对象,你可以传入方法的名字
  • args表示给调用对象以元组的形式提供参数,比如target是函数a,他有两个参数m,n,那么该参数为args=(m, n)即可
  • kwargs表示调用对象的字典
  • name是别名,相当于给这个进程取一个名字
import multiprocessing
from time import ctime,sleep


def music(func,loop):
    for i in range(loop):
        print ("I was listening to %s. %s" %(func,ctime()))
        sleep(1)

def movie(func,loop):
    for i in range(loop):
        print ("I was at the %s! %s" %(func,ctime()))
        sleep(5)
#创建进程组
threads = []
#创建进程t1,添加到进程组,目标函数,以及传参
t1 = multiprocessing.Process(target=music,args=('爱情买卖',2))
threads.append(t1)
#创建线程t1,添加到进程组
t2 = multiprocessing.Process(target=movie,args=('阿凡达',3))
threads.append(t2)

if __name__ == '__main__':
    #启动进程
    for t in threads:
        t.start()
    #守护进程
    for t in threads:
        t.join()
    print ("all over %s" %ctime())

如果要启动大量的子进程,可以用进程池的方式批量创建子进程
python的用多进程池来管理所有的进程,步骤如下:

1)实例化进程池 p=Pool()
2)通过apply_async()函数向进程池中添加进程。
3)通过p.close()函数关闭进程池,关闭之后无法继续添加新的进程。与此同时,CPU开始从进程池中取进程,若CPU有N核,则CPU每次只会取N个进程,待N个进程全部执行完毕,再取出N个。直到将进程池中的进程取完为止。
4)通过p.join()函数等待所有进程被取出并执行完毕。

# 如果有大量进程,则可以用进程池,批量添加
from datetime import datetime
from multiprocessing import Process,Pool
import os,time

def music(func,loop):

    for i in range(loop):
        print ("I was listening to %s. %s" %(func,time.ctime()))
        time.sleep(1)

def movie(func,loop):
    for i in range(loop):
        print ("I was at the %s! %s" %(func,time.ctime()))
        time.sleep(5)

if __name__ =='__main__': #执行主进程
    # 主进程
    print('这是主进程,进程编号:%d' % os.getpid())
    t_start = datetime.now()
    pool = Pool()
    for i in range(8): # CPU有几核,每次就取出几个进程
        pool.apply_async(music, args=('爱情买卖',2))
        pool.apply_async(music, args=('阿凡达',3))
    pool.close() # 调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了
    pool.join() # 对Pool对象调用join()方法会等待所有子进程执行完毕
    t_end = datetime.now()
    print('主进程用时:%d毫秒' % (t_end - t_start).microseconds)

4、进程间通信
multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。

Pipe可以是单项(half-duplex),也可以是双向(duplex)。通过multiprocessing.Pipe(duplex=False)创建单向管道(默认双向)。一个进程从Pipe一端输入对象,然后被Pipe另一端的进程接收,单向管道只允许管道的一端的进程输入,而双向管道从两端输入。

import multiprocessing

def proc1(pipe):
    pipe.send('hello')
    print('procl rec:',pipe.recv())

def proc2(pipe):
    print('proc2 rec:', pipe.recv())
    pipe.send('hello too')

if __name__=='__main__':
    multiprocessing.freeze_support()
    pipe = multiprocessing.Pipe()

    p1 = multiprocessing.Process(target=proc1,args=(pipe[0],))
    p2 = multiprocessing.Process(target=proc2,args=(pipe[1],))

    p1.start()
    p2.start()
    p1.join()
    p2.join()

这里写图片描述

Queue类与Pipe相似,都是先进先出的结构,但是 Queue类允许多个进程放入,多个进程从队列取出对象。Queue类使用Queue(maxsize)创建,maxsize表示队列中可以存放对象的最大数量。

from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

if __name__=='__main__':
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pr,读取:
    pr.start()
    # 等待pw结束:
    pw.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

这里写图片描述

  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值