进程与线程
多线程库threading
方法
Thread(target=func,args=()):创建一个线程对象
local():创建一个ThreadLocal对象
active_count():返回当前存活的线程对象的数量;通过计算len(threading.enumerate())长度而来
current_thread():返回当前线程对象
enumerate():返回当前存在的所有线程对象的列表
get_ident():返回线程pid
main_thread():返回主线程对象,类似 threading.current_thread();只不过一个是返回当前线程对象,一个是返回主线程对象
is_alive():是否存活
同步
acquire()/release():获得/释放 Lock
Lock
多个线程同时acquire时,只能获取一把锁,其他线程等待到获得锁为止
可重入锁,也叫做递归锁 RLock
在需要重复获得锁的情况下(如:递归调用)避免死锁!!!
多个线程同时acquire时,都可以获得锁,所以acquire,release必须成对
Condiftion
wait():线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。调用wait()会释放Lock,直至该线程被Notify()、NotifyAll()或者超时线程又重新获得Lock.
notify(n=1):通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动释放Lock。
notifyAll():如果wait状态线程比较多,notifyAll的作用就是通知所有线程(这个一般用得少)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46#!/usr/bin/python3.4
# -*- coding: utf-8 -*-
import threading, time
def Seeker(cond, name):
time.sleep(2)
cond.acquire()
print('%s :我已经把眼睛蒙上了!'% name)
cond.notify()
cond.wait()
for i in range(3):
print('%s is finding!!!'% name)
time.sleep(2)
cond.notify()
cond.release()
print('%s :我赢了!'% name)
def Hider(cond, name):
cond.acquire()
cond.wait()
for i in range(2):
print('%s is hiding!!!'% name)
time.sleep(3)
print('%s :我已经藏好了,你快来找我吧!'% name)
cond.notify()
cond.wait()
cond.release()
print('%s :被你找到了,唉~^~!'% name)
if __name__ == '__main__':
cond = threading.Condition()
seeker = threading.Thread(target=Seeker, args=(cond, 'seeker'))
hider = threading.Thread(target=Hider, args=(cond, 'hider'))
seeker.start()
hider.start()
执行结果:
seeker :我已经把眼睛蒙上了!
hider is hiding!!!
hider is hiding!!!
hider :我已经藏好了,你快来找我吧!
seeker is finding!!!
seeker is finding!!!
seeker is finding!!!
seeker :我赢了!
hider :被你找到了,唉~^~!Semaphore和BoundedSemaphore
Semaphore:Semaphore 在内部管理着一个计数器。调用 acquire() 会使这个计数器 -1,release() 则是+1(可以多次release(),所以计数器的值理论上可以无限).计数器的值永远不会小于 0,当计数器到 0 时,再调用 acquire() 就会阻塞,直到其他线程来调用release()
Bmaphore:类似于Semaphore;不同在于BoundedSemaphore 会检查内部计数器的值,并保证它不会大于初始值,如果超了,就引发一个 ValueError。多数情况下,semaphore 用于守护限制访问(但不限于 1)的资源,如果 semaphore 被 release() 过多次,这意味着存在 bug
系统交互库subprocess
特性
- 多用于调用外部程序
- 只通过管道进行文本交流
方法
call():执行命令,并返回执行状态,其中shell参数为False时,命令需要通过列表的方式传入,当shell为True时,可直接传入命令
check_call():用法与subprocess.call()类似,区别是,当返回值不为0时,直接抛出异常
check_output():用法与上面两个方法类似,区别是,如果当返回值为0时,直接返回输出结果,如果返回值不为0,直接抛出异常。需要说明的是,该方法在python3.x中才有。
Popen():在一些复杂场景中,我们需要将一个进程的执行输出作为另一个进程的输入。在另一些场景中,我们需要先进入到某个输入环境,然后再执行一系列的指令等,该方法有以下参数:
args:shell命令,可以是字符串,或者序列类型,如list,tuple。
bufsize:缓冲区大小,可不用关心
stdin,stdout,stderr:分别表示程序的标准输入,标准输出及标准错误
shell:与上面方法中用法相同
cwd:用于设置子进程的当前目录
env:用于指定子进程的环境变量。如果env=None,则默认从父进程继承环境变量
universal_newlines:不同系统的的换行符不同,当该参数设定为true时,则表示使用\n作为换行符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n')
obj.stdin.write('print 2 \n')
obj.stdin.write('print 3 \n')
obj.stdin.write('print 4 \n')
obj.stdin.close()
cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()
print cmd_out
print cmd_error1
2
3
4
5
6
7#将一个子进程的输出,作为另一个子进程的输入:
import subprocess
child1 = subprocess.Popen(["cat","/etc/passwd"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["grep","0:0"],stdin=child1.stdout, stdout=subprocess.PIPE)
out = child2.communicate()
- 异步高级封装接口
concurrent.futures
ThreadPoolExecutor
,ProcessPoolExecutor
1
2
3
4
5
6
7
8with futures.ThreadPoolExecutor(workers) as executor:
res = executor.map(func, iter)
executor = ThreadPoolExecutor(max_workers=2)
a = executor.submit(funca)
b = executor.submit(funcb)
resa = a.result()
resb = b.result()ProcessPoolExecutor
使用方式与ThreadPoolExecutor
一样 多进程管理包multiprocessing
- 待续