Python多线程--HowTo

1 queue 模块

queue 模块实现了多生产者、多消费者队列。可以方便在不同的线程之间传递信息。

1.1 Queue

模块中实现了三种类型的 queue ,即 FIFO 队列, LIFO 队列和 Priority 队列。分别由类 queue.Queue queue.LifoQueue queue.PriorityQueue 实现。各个类在定义对象时,可以指定队列的最大长度,无指定的话为无限大。

1.2 Queue 类对象的操作

名称

语义

qsize()

用于返回队列当前的大小

empty()

返回队列是否为空

put(item [,block [,timeout]]

向队列中插入一条记录。默认 block = True, timeout = None ,操作会在队列满时阻塞直到可以插入后返回,如果 timeout  为正,则在队列满时阻塞 timout 后抛出 Full 异常。如果 block = False ,则在队列满时立即返回并抛出 Full 异常。 = put_nowait(item)

get([block [,timeout]]

从队列中删除一条记录并将其返回。默认 block = True, timeout = None ,操作会在队列空时阻塞直到可以从中取出一条记录,如果 timeout 为正,则阻塞时间超时后,抛出 Empty 异常。如果 block=False ,则在队列为空时立即返回并抛出 Empty 常。 =get_nowait()

task_down()

通知上一个队列操作已经完成。消费者线程在 get() 条目后,在完成相应工作后,需要调用 task_done() 以告知队列处理任务已经完成。如果 task_down() 调用次数超过队列中元素个数,则抛出 ValueError 异常。

join()

阻塞一直到队列中所有 items 都被 get() 并处理。

2 高级线程操作 threading 模块

2.1 模块的方法

名称

语义

active_count()

返回 Thread 对象的个数

Condition()

返回一个条件变量对象

current_thread()

返回当前线程对象

enumerate()

返回当前活动线程 list

Event()

返回一个事件对象

lock()

返回一个锁的对象

Rlock()

返回一个可重入的锁对象

Semaphore(val=1)

返回一个信号量的对象

settrace(func)

为所有生成线程设置跟踪函数, func 会传递给 sys.settrace()

setprofile(func)

为所有生成线程设置计量函数, func 会传递给 sys.setprofile()

stack_size(size)

设置线程的栈大小,全局有效

2.2 Thread 类对象的方法

名称

语义

Thread(group=none,target,name,arg,dicarg)

生成一个线程,执行例程为 target ,默认 target=None ,此时应由用户继承 Thread 类,并重载 run() ,派生类务必调用基类 __init__

start()

启动线程

run()

线程运行例程

getName()/ setName()

获得 / 设置线程名称,可直接访问 name 成员,名称具有 Thread_N 的形式 ,N 为自然数

is_alive()

线程是否存活

setDaemon(Ture)

将线程设置为后台运行,可访问 daemon 成员

2.3 Lock 类对象的方法

名称

语义

acquire(blocking=True)

获取锁,如果 blocking=False ,则类似 try_acquire()

release()

释放锁

2.4 RLock 类对象

可重入的锁是指线程可以多次锁住它的锁。它使用属主线程和迭代层次的概念以及已锁和未锁状态。当一个线程已经拥有一个锁时,再次调用 acquire() 将使迭代层次增加 1 ,并立即返回。但如果其他线程锁住了锁,则将导致阻塞。

2.5 Condition 对象

名称

语义

Condition(lock=None)

构造一个条件变量,不使用外部锁进行关联。

acquire(*args)

锁住条件变量关联的内部锁

release()

释放条件变量关联的内部锁

wait(timeout=None)

等待条件变量上事件,等待 notifiy 或超时

notify()

唤醒等待在条件变量上的线程

notify_all()

广播事件

2.6 Semaphore 类对象

名称

语义

Semaphore(value=1)

构造一个信号量,默认并发度为 1

BoundedSemaphore(value=1)

 

acquire(blocking=True)

P 操作,如果 blocking=False ,则类似 try_acquire()

release()

V 操作

2.7 Event 类对象

名称

语义

Events()

声明一个事件对象,内部有一个 flag

is_set()

flag 是否设置

set()

 

clear()

 

wait(timeout=None)

阻塞直到 flag 变为 True

可以用于在线程间进行简单的通信。

2.8 Timer

名称

语义

Timer(interval,func,args=[],kwarg={})

声明一个线程每隔 interval 就执行 func

cancel()

停止 Timer 对象

1 :由于锁,条件变量,信号量都声明了 acquire() release() ,因此可以在 with 上下文管理语句中使用。

2 :如果系统没有提供 threading 模块,需要导入 dummy_threading 模块提供相应的接口

 

3 低级线程操作 _thread

语句

语义

start_new_thread(func,args[,kwargs]

启动一个线程

interrupt_main()

向主线程发送 key_interupt 异常

exit()

发送 SystemExit 异常

allocate_lock()

返回新的锁对象

lock.acquire()

 

lock.release()

 

lock.locked()

 

注:如果系统没有提供 _thread 库,可以加载 dummy_thread 迭代

 

4 Python 多线程程序示例

   

 

5 你需要 Python 多线程吗?

5.1 GIL 全局解释器锁

全局解释器锁 (Global Interpretor Lock) 说明 Python 解释器并不是线程安全的。当前线程必须持有全局锁,以便对 Python 对象进行安全地访问。因为只有一个线程可以获得 Python 对象 /C API ,所以解释器每经过 100 个字节码的指令,就有规律地释放和重新获得锁。解释器对线程切换进行检查的频率可以通过 sys.setcheckinterval() 函数来进行控制。

需要说明的是,因为 GIL CPU 受限的应用程序将无法从线程的使用中受益。使用 Python 时,建议使用进程,或者混合创建进程和线程。

5.2 Python 多线程的效率

由于 GIL 的存在, Python 并不是在多线程之间对共享数据进行加锁,而是采用了宏锁,一次只有一个线程运行于解释器中,多个线程只能在各自的时间片中访问解释器,并不能利用多核的优势,因为在系统看来,解释器只有一个进程。

在上面的例子中,由于工作是 CPU 密集型的,因此左边的线性工作更加快,因为 GIL 的存在,两个线程切换工作需要消耗时间。

下面来测试一下对于计算型和I/O型的操作,Python单个线程与多线程间的时间差异来看我们上面的分析是否正确:

代码mythread.py

 

测量代码:


结果:

[20.63806740800856, 20.339483649458241, 20.328089463884382]
[20.958624909031741, 21.177667552719697, 21.003685663960084]

[4.9799982958727993, 4.9634425604371497, 4.9663161100083961]
[4.9650368971475434, 4.9747188539325542, 6.4271900478971489]

 

6 相关资料

GIL介绍 http://www.pyzine.com/Issue001/Section_Articles/article_ThreadingGlobalInterpreter.html

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值