因为 multiprocessing 模块不支持交互模式,只有在终端输入 python xxx.py 才会很好运行。
pip 升级
python3 -m pip install --upgrade pip
调用 thread 模块中的 start_new_thread () 函数来产生新线程。语法如下:
thread.start_new_thread(function, args[, kwargs])
参数说明:
- function - 线程函数。
- args - 传递给线程函数的参数,他必须是个 tuple 类型。
- kwargs - 可选参数。
python3 中它已经被 OUT 了。
Threading 模块创建线程使用 Threading 模块创建线程,直接从 threading.Thread 继承,然后重写 init 方法和 run 方法。
threading模块除了Thread类之外,还包括许多好用的同步机制:
# 创建锁
threadLock = threading.Lock()
# 获得锁,成功获得锁定后返回True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回False
threadLock.acquire()
print_time(self.name, self.counter, 3)
# 释放锁
threadLock.release()
线程优先级队列
Python 的 queue 模块中提供了同步的、线程安全的队列类,包括 FIFO(先入先出) 队列 queue,LIFO(后入先出)队列 Lifoqueue,和优先级队列 Priorityqueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。
queue 模块中的常用方法:
- queue.qsize () 返回队列的大小
- queue.empty () 如果队列为空,返回 True, 反之 False
- queue.full () 如果队列满了,返回 True, 反之 False
- queue.full 与 maxsize 大小对应
- queue.get ([block [, timeout]]) 获取队列,timeout 等待时间
- queue.get_nowait () 相当 queue.get (False)
- queue.put (item) 写入队列,timeout 等待时间
- queue.put_nowait (item) 相当 queue.put (item, False)
- queue.task_done () 在完成一项工作之后,queue.task_done () 函数向任务已经完成的队列发送一个信号
- queue.join () 实际上意味着等到队列为空,再执行别的操作
import queue
workqueue = queue.Queue(10)
Python 的进程
multiprocessing包
Process通过 multiproessing 可以轻松完成从单进程到并发执行的转换。
multiprocessing 支持子进程、通信和共享数据、执行不同形式的同步,提供了 Process、Queue、Pipe、Lock 等组件。
在 multiprocessing 中,每一个进程都用一个 Process 来表示。
- target: 表示调用对象,可以传入方法的名字。
- args:b表示被调用对象的位置参数元组,比如 target 是函数 a, 他有两个参数 m,n ,那么 args 就传入 (m,n) 即可。
- kwargs:表示调用对象的字典。
- name:是别名,相当于给这个进程去一个名字。
- group:分组,实际上不适用。
active_children()multiprocessing.cpu_count() 可以获得当前机器的 CPU 核心数量。
自定义进程类multiprocessing.active_children() 可以获得当前所有运行的进程。
deamon自定义进程类是通过集成 Process 类,实现对 run() 方法重写。
deamon 属性 和 join() 方法multiprocessing.deamon 属性如果等于 true,说明当父进程结束后,子进程会自动被终止。
Lock 锁当 deamon 属性等于 true 时,等子进程执行完再结束,就需要用到 join() 方法。
Semaphore当两个进程同时进行了输出,归根结底是因为现成同时资源(输出操作)而导致的,通过锁来实现进程间的“互斥”。
Queue信号量,控制临界资源的数量,保证各个进程之间的互斥和同步。
Pipemultiprocessing.Queue 不同于 普通的 list ,它作为进程通信的共享队列使用。一个进程向队列中放入数据,然Producer put 0.3693465539319044后另一个进程取出数据。
Pool管道,一端发一端收,Pipe 可以说单向,也可以是双向。
通过 multiprocessing.Pipe(duplex=False) 创建单向管道(默认为双向),一个进程从 Pipe 的一端输入对象,然后被 Pipe 另一端进程接收。单向管道只允许管道一端的进程输入,双向管道允许两端输入。
Pool 和 Map进程池,Pool 可以提供制定数量的进程,供用户调用。当有新的请求提交到 pool 中时,如果池还没有满,就会创建一个新的进程来执行该请求。如果池中的已经达到最大值,那么请求就会等待,知道池中有线程结束,才会创建新的进程来处理它。
Pool 的用法有阻塞和非阻塞两种方式,阻塞即为添加进程后,不一定非要等待该进程执行完之后添加其他进行允许,阻塞则相反。
close () 关闭 pool,使其不在接受新的任务。 terminate () 结束工作进程,不在处理未完成的任务。 join () 主进程阻塞,等待子进程的退出, join 方法要在 close 或 terminate 之后使用。 当然每个进程可以在各自的方法返回一个结果。apply 或 apply_async 方法可以拿到这个结果并进一步进行处理。
如果你现在有一堆数据要处理,每一项都需要经过一个方法来处理,那么 map 非常适合。 比如现在你有一个数组,包含了所有的 URL,而现在已经有了一个方法用来抓取每个 URL 内容并解析,那么可以直接在 map 的第一个参数传入方法名,第二个参数传入 URL 数组。