Python学习笔记(十)
一、并发编程
(一)基础概念
1、并发和并行
并行:
同时运行,只有具备多个CPU才能实现并行
并发:
是伪并行,即看起来是同时运行(并行也属于并发)
并发 = 任务切换 + 状态保存
2、同步和异步
同步:
发送方发送请求之后,需要等接收方发回响应后才接着发
异步:
发送方发送一个请求之后不等待接收方响应这个请求,就继续发送下个请求
3、阻塞和非阻塞
阻塞:
调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回,该线程在此过程中不能进行其他处理
非阻塞:
调用结果不能马上返回,当前线程也不会被挂起,而是立即返回执行下一个调用。(网络通信中主要指的是网络套接字Socket的阻塞和非阻塞方式,而soket 的实质也就是IO操作)
(二)线程
线程是CPU的最小执行单位,进程:资源单位
1、threading 模块
(1)创建线程(两种方式)
方法一:实例化Thread类,把函数传入构造函数
threading.Thread(target=目标函数名,args=(参数,))
方法二:继承Thread类,重写run方法
(2)常用方法
① Thread类方法
方法名 | 作用 |
---|---|
.start() | 启动线程 |
.join() | 要求主线程等待 |
.getName() | 返回线程名 |
.name(等同于.getName()) | 线程名称 |
.setName() | 设置线程名 |
isAlive() | 返回线程是否是活动的 |
② threading模块方法
方法名 | 作用 |
---|---|
threading.currentThread() 或 threading.current_thread() | 返回当前的线程 |
threading.activeCount() | 返回正在运行的线程数 |
2、同步锁
当多个线程共享数据时,会发生数据的抢占现象,解决方法:同步锁
threading.Lock
.acquire():上锁
.release():释放锁
支持上下文操作 with lock:
其中lock为Lock对象
注意:使用上下文操作就不用上锁和释放锁了
3、线程池
使用时需要导入concurrent 包下的 ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor,
def get_html(times):
time.sleep(times)
print("get page {} success".format(times))
return times
executor = ThreadPoolExecutor(max_workers=32)
task1 = executor.submit(get_html, (3,))
task2 = executor.submit(get_html, (2,))
task3 = executor.submit(get_html, (3,))
常用方法
方法名 | 作用 |
---|---|
.submit() | 提交执行的函数到进程池 |
.cancel() | 任务还没有开始,可以使用此方法取消 |
(三)进程(multiprocessing)
充分运用多核、多CPU的计算能力,适用于计算密集任务
创建进程(和线程一样)
实例化multiprocessing模块中的Process类,把参数传入构造函数
multiprocessing.Process(target=目标函数,args=(参数,))
.start()
启动进程
.join()
主进程等待子进程结束
(四)队列(queue 模块)
- .Queue(maxsize=0):构造函数
- .put(item, block=True, timeout=None):放入数据
- .get(block=True, timeout=None):获取数据
- .task_done():声明当前队列任务处理完毕
二、装饰器
(一)概述
1、用于管理和增强函数和类行为的代码
2、提供一种在函数或类定义中插入自动运行代码的机制
3、装饰器可以从函数或者类中抽离出大量与函数功能本身无关的高频使用代码并重用它们
4、简言之装饰器的作用就是为已经存在的对象(函数或者类)添加额外的功能。
(二)使用
1、不带参数装饰器
(1)不带参数和返回值
import time
#原函数如下
def foo():
print 'test foo()'
# 定义外封装函数,传入待封装函数,并返回另一个附加计时功能的函数
def timef(func):
# 定义一个内嵌的包装函数,给传入的函数加上计时功能,该函数参数接口同传入函数
def wrapper():
start = time.clock()
func()
end =time.clock()
print 'time:', end - start
# 将包装后的函数返回
return wrapper
foo = timef(foo)
foo()
import time
def timef(func):
def wrapper():
start = time.clock()
func()
end =time.clock()
print 'time:', end - start
return wrapper
@timef
def foo():
print 'test foo()'
foo()
(2)带参数和返回值
def dec(func):
def wrapper(a, b):
print("before myfunc().")
ret = func(a, b)
print("after myfunc(),result: %s" % ret)
return ret
return wrapper
@dec
def add(a, b):
print(" add(%s,%s) is called." % (a, b))
return a + b
add(1, 2)
(3)参数个数不确定
def dec(func):
def wrapper(*args, **kwargs):
print("before %s." % func.__name__)
ret = func(*args, **kwargs)
print("after %s,result: %s" % (func.__name__, ret))
return ret
return wrapper
@dec
def add1(a, b):
print(" add1(%s,%s) called." % (a, b))
return a+b
@deco
def add2(a, b, c):
print(" add2(%s,%s,%s) called." % (a, b, c))
return a+b+c
add1(1, 2)
add2(1, 2, 3)
2、带参数装饰器
def pre_dec(arg):
def dec(func):
def _dec():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return _dec
return dec
@pre_dec("mytest")
def func():
print("func() called.")
func()
3、使用类创建装饰器
- 在构造函数中加入函数名参数
- 实现__call__(self)方法
- 使用的函数前加@类名
(三)装饰器顺序
@f1
@f2
等同于
test = f1(f2(test))
test()