轻松实现Python中的多进程与多线程

快动动手指!

今天我们来聊聊Python里面的多进程与多线程编程模式。

01 多线程工作

在开始讲今天的正文之前,先给大家介绍一个概念「多线程工作」,这个概念可能有的人听过,也可能有的人平常工作中就是这么做的。我再来给大家讲讲这个概念,所谓的「多线程工作」就是同时做好几件事情。

拿我个人工作中例子来说,当我用Sql跑数的时候,数据不可能一下子就导出来,我会在一个屏幕上显示Sql运行进度,在另一个屏幕上先做一会PPT,等Sql跑出来以后,我就又会迅速切换到处理刚刚导出来的数据。有的时候数据量很大,用Excel打开文件可能需要几分钟的时间,这个时候Excel是处于运行状态,我是没法在Excel上做别的事情,我会去微信上去处理别人的一些问题,当文件打开以后,我会迅速切换到Excel上继续下一步处理,当我输入一个公式以后,Excel可能又需要等待一会,这个时候我就可以再去做一些别的事情。

大家可以看到,我没有在等一件事情彻底做完以后再去做另一件事情,而是在不同事情之间迅速切换,这种工作方式就可以算是一种「多线程工作」。

「多线程工作」可以减少你等待的时间,大大提高你的工作效率。

02 多进程与多线程

了解了「多线程工作」以后,我们开始进入今天的正题,编程里面的多线程和多进程。在上面的例子中Sql跑数可以算是一个进程、做PPT也可以算是一个进程、Excel处理数据还是一个进程。

进程下面还有一个更小的单位就是线程,一个进程由若干个线程组成,Sql跑数这个进程可以由写Sql、运行Sql、导出数据这几个线程组成。同样,PPT制作这个进程可以由明确主题、选模板、列大纲、丰富页面这几个线程组成。

线程是程序执行的最小单位,一个进程可以由一个或多个线程组成,各个线程之间也是交叉执行。

这里需要注意的是,多进程/多线程并不能做到同时去做好几件事情,而是把不同的事情交叉着做,做一段时间任务a,然后强制停止,去做一会任务b,再停止,再去做任务c。之所以会觉得各个任务之间是同时进行的原因是是任务与任务之间切换速度足够快,这样看起来就像是多个任务同时在进行。

我们再来看两个概念:

并行:指在同一时刻,有多条指令在多个处理器上同时执行;
并发:指在同一时刻,只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

多份工作有多个人同时在做时就是并行,当多份工作由一个人交替在做时就是并发。在计算机中也是同样的概念,计算机中CPU的核数就相当于人数,当计算机是单核多任务时就是并发;当计算机是多核且大于任务数时,就是并行。

目前电脑主流配置都是四核/八线程的,而实际工作的任务数大都大于四个,所以也是需要交替来执行具体任务的,也就是并发执行。

我电脑运行情况

上面就是关于多线程与多进程的一个简单通俗的理解,一些太官方的解释我就不在这里放了,大家感兴趣的可以去自行上网查。

03 多进程与多线程是如何提高效率的

假设做任务A需要1个小时、任务B需要1个小时、任务C需要一个小时,当我们每个任务做20分钟以后切换到另一个任务,这样做完三个任务需要的总时间是不会变的,不仅不会变,反而可能会增加,因为在不同任务之间切换是需要代价的,因为当你从一个任务切换到另一个任务时很有可能不记得刚刚做到哪里了,还需要花时间想一想。那既然是这样,我们为什么还要用多进程/多线程这种处理任务的方式呢?我在第一小节里面提过,「多线程工作」可以减少你等待的时间,大大提高你的工作效率。

是因为在实际工作中,有很多需要等待的地方,比如等待Excel打开,等待Sql跑出数据。多进程/多线程任务处理方式就是充分利用这些等待时间。让你的大脑,计算机的大脑(CPU)得到充分的利用。如果要是没有等待的时间,多进程/多线程的任务处理方式可能就不如单线程的了。

04 多进程与多线程是如何实现的

了解清楚了多进程与多线程是什么,以及是如何提高处理任务的效率的以后,我们进入到硬干货部分,那就是具体多进程/多线程如何实现“同时”处理多任务的。

实现多任务的方式主要有以下几种:

1、多进程模式
2、多线程模式
3、多进程+多线程

同时执行多个任务通常各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务1必须暂停等待任务2完成后才能继续执行,有时,任务3和任务4又不能同时执行,所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程单线程的程序。

4.1多进程模式

多进程就是一次启动多个进程,每个进程只有一个线程,但多个进程可以一起执行多个任务。一般进程数默认是电脑CPU核数,当你的电脑是四核的时候,你的电脑进程默认就是4个。

4.1.1参数详解

在Python中我们借助多进程包multiprocessing来进行多进程任务处理方式, multiprocessing模块提供了一个Process类来代表一个进程对象,

#Process参数
multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

#group分组
#target表示调用对象,即函数
#name表示进程的别名
#args表示调用对象的位置参数元组,即函数的参数
#kwargs表示调用对象的字典

#Process常用方法close() 关闭进程is_alive() 进程是否在运行join() 等待join语句之前的所有程序执行完毕以后再继续往下运行,通常用于进程间的同步start()  进程准备就绪,等待CPU调度run()  strat()调用run方法,如果实例化进程时没有传入target参数,这star执行默认run()方法

#Process常用属性
pid 进程ID
name 进程名字

4.1.2建立一个子进程

下面的例子演示了启动一个子进程(即单进程)并等待其结束:

from multiprocessing import Processimport os

# 子进程要执行的代码def run_proc(name):    print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':    print('Parent process %s.' % os.getpid())#用来获取主进程的进程ID    p = Process(target=run_proc, args=('test',))#实例化进程p,调用run_proc函数,传入参数对象args    print('Child process will start.')    p.start()#进程准备就绪    p.join()#待所有进程执行完毕以后执行后续操作    print('Child process end.')

运行结果如下:

Process (876) start...
I (876) just created a child process (877).
I am child process (877) and my parent is 876.

一个子进程其实就和我们平常调用单一函数是一样的。

4.1.3建立多个子进程

建立多个子进程(即多进程),其实就是多个函数随机同步运行。

建立多进程有两种方法,一种是直接利用Process来建立多个子进程即可,如下:

from multiprocessing import Processimport random,time

def do_task(task):    print('我正在做{}'.format(task))    time.sleep(random.randint(1,3))

def write_task(task):    print('我正在写{}'.format(task))    time.sleep(random.randint(1,3))

if __name__ == '__main__':    p1 = Process(target=do_task,args=('PPT',))    p2 = Process(target=write_task,args=('Sql',))    p1.start()    p2.start()

输出结果为:

我正在做PPT
我正在写Sql

上面代码表示同时启动两个进程,且两个进程分别调用不同的函数,即做不同的任务。而且上面的任务数只有两个,当任务数(需要调用的函数)较多时,我们如果还用上述的方法创建多进程,就需要实例化多个进程对象,并且写多行p.start()比较麻烦,聪明的前辈们肯定不会用这么笨的方法,所以就有了进程池(Pool)。

multiprocessing.Pool = Pool(processes=None)#process为进程数

把上面的二进程用进程池表示以后的结果如下:

import multiprocessing
import random,time

def do_task(task):
    print('我正在做{}'.format(task))
    time.sleep(random.randint(1,3))

def write_task(task):
    print('我正在写{}'.format(task))
    time.sleep(random.randint(1,3))

if __name__ == '__main__':
    func_list=[do_task,write_task]
    args_list=['PPT','Sql']
    pool=multiprocessing.Pool(2)

for func,args in function_list,args_list:
            pool.apply_async(func,arg)   
    print 'Waiting for all subprocesses done...'
    pool.close()
    pool.join()    #调用join之前,一定要先调用close() 函数,否则会出错
    print 'All subprocesses done.'

输出结果如下:

Waiting for all subprocesses done...我正在做PPT我正在写SqlAll subprocesses done.

4.2多线程模式

多线程模式就是一次只启动一个进程,但是在这个进程里面可以启动多个线程,这样多个线程就可以一起执行多个任务,在Python中我们要启动多线程借助于threading模块,用于 启动多线程的模块还有_thread模块,但是threading模块是封装了_thread模块,且比较高级,所以我们一般使用threading模块即可。

4.2.1参数详解

启动多线程使用的是threading模块中的Thread类,构建时使用的参数和方法与Process基本一致,大家看看即可,这里就不赘述了。

#参数
Thread(group=None, target=None, name=None, args=(), kwargs={}) 
#方法
isAlive()
get/setName(name) 获取/设置线程名
start()   
join()

4.2.2创建一个线程

创建一个线程就是调用一个函数。

import time, threading

def do_chioce(task):    print('我正在{}'.format(task))    time.sleep(random.randint(1,3))

if __name__ == '__main__':    t = threading.Thread(target=do_chioce,args=('选PPT模板',))    t.start()

输出结果为:

我正在选PPT模板

4.2.3创建多个线程

创建多个线程就是调用多个函数。

import time, threading

def do_chioce(task):    print('我正在{}'.format(task))    time.sleep(random.randint(1,3))

def do_content(task):    print('我正在{}'.format(task))    time.sleep(random.randint(1,3))

if __name__ == '__main__':    t1 = threading.Thread(target=do_chioce,args=('选PPT模板',))    t2 = threading.Thread(target=do_content,args=('列PPT大纲',))    t1.start()    t2.start()

输出结果为:

我正在选PPT模板
我正在列PPT大纲

4.3多进程+多线程

多进程+多线程就是一次启动多个进程,每个进程又启动多个线程,这样同时执行的任务就会很多,但是模型相对复杂,不建议使用。

每天进步一点点:数据分析1480

(0)

相关推荐

  • 简单明了的 Python 多线程来了

    线程和进程   计算机的核心是CPU,它承担了所有的计算任务,就像是一座工厂在时刻运行. 如果工厂的资源有限,一次只能供一个车间来使用,也就是说当一个车间开工时其它车间不能工作,也就是一个CPU一次只 ...

  • 这样学 Python 多线程与进程(一)

    第一时间获取 Python 技术干货! 阅读文本大概需要 5 分钟. 众所周知,Python 中的多线程是一个假的多线程,对于多核 CPU,由于受限于 GIL 全局解释锁,同一时刻只能有一个线程在运行 ...

  • 编程语言Python进程和线程保姆式教学,1个台机子多只手干活的秘籍

    进程线程有多重要?刚开始学Python的时候你可能还没有感觉到,因为你写的代码从上到下执行一遍就可以了,但实际上这很初级,实际开发写项目的时候,为了充分利用电脑配置来加快程序进度,我们往往会用到多进程 ...

  • C#多线程编程(二)线程池与TPL

    一.直接使用线程的问题 每次都要创建Thread对象,并向操作系统申请创建一个线程,这是需要耗费CPU时间和内存资源的. 无法直接获取线程函数返回值 无法直接捕捉线程函数内发生的异常 使用线程池可以解 ...

  • 第48天:初识 Python 多线程

    我们知道,多线程与单线程相比,可以提高 CPU 利用率,加快程序的响应速度. 单线程是按顺序执行的,比如用单线程执行如下操作: 6秒读取文件19秒处理文件15秒读取文件28秒处理文件2 总共用时 28 ...

  • 如何用Python中Tushare包轻松完成股票筛选(详细流程操作)

    如何用Python中Tushare包轻松完成股票筛选(详细流程操作) 本文包括安装以及调用Tushare包的详细流程操作 一.Tushare简介 Tushare是Python中一个十分好用的免费调用股 ...

  • 一个求和函数,轻松解决工作中80%的常见问题,1个顶7个

    一个求和函数,轻松解决工作中80%的常见问题,1个顶7个

  • Python 中的函数装饰器和闭包

    函数装饰器可以被用于增强方法的某些行为,如果想自己实现装饰器,则必须了解闭包的概念. 装饰器的基本概念 装饰器是一个可调用对象,它的参数是另一个函数,称为被装饰函数.装饰器可以修改这个函数再将其返回, ...

  • Python中tuple和list的区别?基础学习!

    想必大家都知道,Python数据类型有很多种,其中有两个对象的写法非常相似,它就是tuple元组和list列表,让人傻傻分不清楚.那么你知道Python中tuple和list有什么区别吗?我们来看看具 ...

  • Python中缩进是什么?入门分享!

    众所周知,Python是一门独特的编程语言,它语法清晰.简单易学,而且Python是通过缩进来识别代码块的,因为一般的语言都是通过{}或者end来作为代码块标记. Python中缩进是什么? 要求严格 ...

  • 女人学会这20招 轻松搞定心中男神

    女生在面对自己喜欢的男生面前往往不知所措,主动追吧觉得不矜持,不主动追又不能跟自己喜欢的人在一起,所以往往很多幸福就在这种犹豫中错过.学会小编今天整理的这20招,就可以轻轻松松的搞定心目中的男神,不用 ...

  • python中的内置函数

    前言 本人只在csdn写博客 内置函数 介绍 一. 数学运算 abs()求绝对值函数 round() 近似取值 pow()求指数 divmod()求商和余数 max()求最大值和min()求最小值 s ...

  • 【Python核心编程笔记】一、Python中一切皆对象

    Python中一切皆对象 本章节首先对比静态语言以及动态语言,然后介绍 python 中最底层也是面向对象最重要的几个概念-object.type和class之间的关系,以此来引出在python如何做 ...

  • 【青少年编程】Python中的分号

    今天有小朋友问我以下的选择题: 关于Python赋值语句,以下选项中不合法的是() A. x = (y=1) B. x, y = y, x C. x = y = 1 D. x = 1; y = 1 这 ...