试想一下当你有1w个小文件需要处理,假设每个文件读取处理到写入需要1秒,那么你处理完所以文件会需要两个多小时。
但是如果你可以同时开启四个任务处理1w 个文件,每个任务平均处理2500个。这个时候你的时间可以压缩在一小时以内。如何同时对一个文件夹开启四个任务同时处理不同的任务,而不会产生冲突?接下来我们一起了解一下多线程和多进程。
进程与线程
从一定意义上讲,进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,进程包含多个线程在运行。
进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源。
一、Python多线程
Python 中提供两个标准库 thread 和 threading 用于对线程的支持,但 Python3 中已放弃对 thread 的支持,所以接下来均以 threading 为例。
Python中有两种方式实现线程:
- 实例化一个 threading.Thread 的对象,并传入一个初始化函数对象作为线程执行的入口;
- 继承 threading.Thread,并重写 run 函数;
1# 第一种实现线程的方法 2import threading 3# my_fun为自定义函数,args为自定义函数的参数 4thread1 = threading.Thread(target=my_fun, args=("This is thread 1",)) 5thread2 = threading.Thread(target=my_fun, args=("This is thread 2",)) 6# 启动线程 7thread1.start() 8thread2.start() 91011# 第二中实现线程的方法12class MyThread(threading.Thread):13 # step 1: call base __init__ function14 def __init__(self, thread_name):15 super(CustomThread, self).__init__(name=thread_name)16 self._tname = thread_name17 # step 2: overide run function18 def run(self):19 print("This is %s running...." % self._tname)20# 实例化MyThread21thread1 = MyThread("thread 1")22thread2 = MyThread("thread 2")23# 启动线程24thread1.start()25thread2.start()
注:
- 两种方式创建线程,指定的参数最终都会传给threading.Thread类;
- 传给线程的目标函数是在基类Thread的run函数体中被调用的,如果run没有被重写的话。
threading.Thread提供的线程对象方法和属性:
1. start():创建线程后通过start启动线程,等待CPU调度,为run函数执行做准备;2. run():线程开始执行的入口函数,函数体中会调用用户编写的target函数,或者执行被重载的run函数;3. join([timeout]):阻塞挂起调用该函数的线程,直到被调用线程执行完成或超时。通常会在主线程中调用该方法,等待其他线程执行完成。4. name、getName()&setName():线程名称相关的操作;5. ident:整数类型的线程标识符,线程开始执行前(调用start之前)为None;6. isAlive()、is_alive():start函数执行之后到run函数执行完之前都为True;7. daemon、isDaemon()&setDaemon():守护线程相关。
二、Python多进程
Python 提供 multiprocessing 用于创建多进程
创建进程的方式和创建线程的方式类似:
- 实例化一个 multiprocessing.Process 的对象,并传入一个初始化函数对象作为新建进程执行入口;
- 继承 multiprocessing.Process,并重写 run 函数;
1# 第一种实现进程的方法 2from multiprocessing import Process 3 4# my_fun为自定义函数,args为自定义函数的参数 5process1 = Process(target=my_fun, args=("This is process 1",)) 6process2 = Process(target=my_fun, args=("This is process 2",)) 7# 启动线程 8process1.start() 9process2.start()10# join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。11process1.join()12process2.join()131415# 第二中实现进程的方法16from multiprocessing import Process 1718class MyProcess(Process):19 def __init__(self, p_name, target=None):20 # step 1: call base __init__ function()21 super().__init__(name=p_name, target=target, args=(p_name,))2223 def run(self):24 # step 2:25 print("Process name: %s, pid: %s " % (self.name, os.getpid()))2627if __name__ == "__main__":28 # 实例化MyProcess29 process1 = MyProcess("process 1")30 process2 = MyProcess("process 2")31 # 启动进程32 process1.start()33 process2.start()34 process1.join()35 process2.join()
三、进程 VS. 线程
是否采用多任务需要考虑任务的类型,我们可以把任务分为CPU密集型和IO密集型。
- CPU密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。
- 涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成
总结:
- CPU密集型:程序需要占用CPU进行大量的运算和数据处理;
- I/O密集型:程序中需要频繁的进行I/O操作;例如网络中socket数据传输和读取等;
由于Python多线程并不是并行执行,因此较适合与I/O密集型程序,多进程并行执行适用于CPU密集型程序;根据任务的需求选择相应的多任务方式,在多文件数据操作、爬虫等任务时相当实用!
End.
爱数据网专栏作者:xiaoyi
作者介绍:数据分析从业者,金融风控爱好者,不定期原创技术分享,努力成为数据分析、金融风控领域的终身学习者、实践者、传播者
个人微信公众号:小一的学习笔记(ID:xiaoyi_learning)
本文为挖数网专栏作者原创文章,未经允许禁止转载,需要转载请微信联系授权(微信号:lovedata0520)
- 我的微信公众号
- 微信扫一扫
- 我的微信公众号
- 微信扫一扫
评论