多任务的概念
- 并行:任务数小于或者等于cpu的核数,那么多个任务是真正意义一起执行。
- 并发: 任务数大于cpu的核数,多个任务轮流执行,由于cpu切换速度特别快,看起来像是一起运行,其实是假象
线程基本概念
线程即是通过导入threading模块,通过threading.Thread创建出来的,它是cup调度的基本单位,也可以理解为执行代码的分支,线程之间的执行是无序的,主线程会等待子线程结束后再退出。但是可以设置守护主线程。
Thread中几个参数的含义:
1.1. group (线程组):默认为None
1.2. target: 指定执行的目标函数,只写函数名
1.3. name:线程名,默认为Thread-1类型
1.4. args,kwarg:传参,分别以元组和字典形式传参
1.5. * : 以命名参数传参
1.6. daemon: 设置守护主线程,默认为False,等同setdaemon(True)
自定义线程
实际上就是重写一个类继承threading.Tread,改写run方法。并且创建类对象后,统一使用start来启动线程,不调用run方法,也不是用target来指定方法来执行。如果子类提供了__init__方法,那么最好使用super来调用父类方法,以免会出错
多线程执行多任务时,可共享全局变量,但是此时会出现资源竞争的问题,会导致输出的结果不准确。
一般来说有两种解决方式:
3.1. 方法一就是线程同步或者说是线程等待,即 线程名.join()让其中一个线程执行完之后再去执行另
一个线程。
3.2. 方法二就是设置互斥锁,在执行之前上锁,执行结束后释放锁。 创建锁:threading.Lock() —>
上锁 lock.acquire —> 释放锁 lock.release 关于死锁,即是一个线程抢到锁后并没有释放锁,解
决方法就只有在用互斥锁的时候在合适的位置和适当的时间将锁释放
进程基本概念
进程的基本概念:
1.1 一个运行起来的程序或者软件就叫做进程
1.2 每次启动一个进程都需要向操作系统索要运行资源,让进程中的线程来执行其对应的代码,所以进程是操作系统分配资源的基本单位
1.3 默认情况下,一个进程只有一条线程,线程是依附在进程里面的,没有进程就没有线程,但可以在进程中创建多条线程
<br>
进程的创建和进程间的通信
2.1 进程的创建:
进程的创建与线程相似,即导入multiprocessing,使用multiprocessing.Process()来创建一个进程,其中的参数与线程含义相同,但没有 * 和 daemon 这两个参数,运行同样使用start来启动进程
2.2 进程间的通信:
由于进程之间不共享全局变量,原因是子进程相当于是主进程的副本,所以同个设备间的进程通信使用Queue队列
2.2.1 queue队列
创建: multiprocessing.Queue(数字)数字代表该队列的最大消息个数,队列之中可以存放任何类型的数据
queue中的几种用法:
① 向队列中放入数据统一使用queue.put( )
② 在队列中取出数据统一使用queue.get(),数据取出的顺序和放入的顺序相同
③可以用queue.full()判断队列中数据是否已满,若已满,则put将会堵塞,直到队列有空间<br> 可以存放数据
④ 可以用queue.empty()来判断队列是否为空,若为空则get会堵塞,直到有数据可取,但<br> 是该方法可能会发生错误,所以一般在查看前使用一定的延时操作,或者使用<br> queue.size()来获取队列中数据的个数(Mac不适用)。
进程池
概念 : 顾名思义,进程池就是存放着进程的盒子,进程池可以根据需要自行创建进程,会合理的利用进程池中的进程去完成多任务,可以节省资源开销
用法 :
- 创建 multiprocessing.Pool(数字) 其中的数字代表进程池中进程的个数
- 对于进程池来说,异步执行时主进程不会等待其完成任务后再退出。所以,想要将进程池中的进程将任务完成,就要先将进程池关闭pool.close()然后再设置等待pool.join()
进程池间的通信:
同样通过队列来进行通信,只是创建方法不同,进程池中的Queue队列通过multiprocessing.Manage().Queue()创建
进程池中程序的执行:
- 同步执行 即一个结束后下一个执行 : pool.apply()
- 异步执行 即 pool.apply_async( )异步执行时会返回一个对象,该对象有一个wait()方法,可让下一个异步任务等该任务结束后再执行
进程与线程的区别
- 进程是操作系统资源分配的基本单位,每启动一个进程都需要向操作系统索要运行资源,默认一个进程只有一个线程,线程是依附在进程里面的
- 线程是cpu调度的基本单位, 通过线程去执行进程中代码, 线程是执行代码的分支
- 多进程开发比单进程多线程开发稳定性要强,但是多进程开发比多线程开发资源开销要大
- 多进程开发某个进程死了不会影响其它进程的运行,但是多线程开发该进程死了那么这些线程都要进行销毁