python多线程

python程序解释依靠解释器主循环,主循环中同时只能有一个控制线程在运行,类似单核CPU,是伪并发,python保证只有一个线程运行的机制是使用全局解释器锁GIL,如下:

1.设置GIL

2.切换一个线程运行

3.执行指定数量的字节码指令或者线程yielding

4.设置线程为睡眠状态

5.解锁GIL

调用外部代码比如C或者C++的时候,GIL会保持锁定,因为此时没有python字节码指令,

python提供了一些模块用于支持多线程编程,有thread,threading,Queue等,一般不使用thread模块,因为缺少同步原语,主线程退出之后,其他线程都会在没有清理的情况下直接退出,需要使用很笨拙的方法实现等待所有子进程,且没有任何方法可以实现守护进程

thread模块组件:

start_new_thread(function, args, kwargs=None):核心函数,创建线程,第一个参数是函数或者对象,第二个参数是函数参数,必须使用元组,没有参数的话传入空元组

allocate_lock:分配LockType锁

exit():线程退出

LockType锁对象的方法:

acquire(wait=None):尝试获取锁

locked():获取锁对象,成功返回True,否则返回False

release():释放锁

thread模块实现同步的两种笨拙方法:

1.主线程等待子线程执行的最长时间

2.每个字线程获取一个锁,主线程循环检查所有锁都被释放

threading模块组件:

Thread:表示一个执行线程的对象

Lock:锁原语对象,和thread模块一样

RLock:可重入锁,单个线程可以再次获取已持有的锁,即递归锁

Condition:条件变量

Event:一定数量的线程等待某个事件发生,之后所有线程被激活

Semaphore:信号量

Timer:和Thread类似,含有定时器的线程,运行前要等待一段时间

Thread对象数据属性:

name:线程名

ident:线程标识符

daemon:是否是守护线程

Thread对象方法:

__init__(group=None, target=None, name=None, args=(), kwargs={}, verbose=None, daemon=None):实例化一个线程对象

start():执行线程

run():定义线程功能的方法,用于在子类中重写

join(timeout=None):等待指定线程执行结束直到超时

getName():返回线程名

setName(name):设置线程名

isAlive():线程是否存活

isDaemon():是否是守护线程

setDaemon(daemonic):设置守护线程标记,必须在start()之前设置才能生效

Thread类创建线程的三种通用解决方案:

1.创建Thread类的实例,传入一个函数

2.创建Thread类的实例,传入一个可调用的类实例

3.派生Thread类的子类,并创建子类的实例

python中函数是对象,因此给类定义__call__方法之后,可以使用方案2,但是代码比较晦涩而且本质上和方案1没有差别,因此一般使用方案1和方案3

一个使用子类的解决方案如下:

# -*- coding: UTF-8 -*-
#!/usr/bin/env python

import threading
from time import sleep, ctime

loops = [4, 2]

#继承threading.Thread类的一个子类
class MyThread(threading.Thread):
    def __init__(self, func, args, name = ''):
        #调用父类的初始化函数
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args

    #重写run方法,使用start创建线程之后,会调用run方法
    def run(self):
        self.func(*self.args)

#线程方法
def loop(nloop, nsec):
    print 'start loop ', nloop, ' at ', ctime()
    sleep(nsec)
    print 'loop ', nloop, ' done at ', ctime()

def main():
    print 'starting at ', ctime()
    threads = []
    nloops = range(len(loops))

    #创建threading.Thread的子类的实例
    for i in nloops:
        t = MyThread(loop, (i, loops[i]), loop.__name__)
        threads.append(t)

    #创建线程
    for i in nloops:
        threads[i].start()

    #主线程等待所有线程结束
    for i in nloops:
        threads[i].join()

    print 'all done at ', ctime()

if __name__ == '__main__':
    main()

一般将子类单独做成一个模块,这样可以在其他python文件中import,通用模版如下:

# -*- coding: UTF-8 -*-
#!/usr/bin/env python

import threading
from time import ctime

class MyThread(threading.Thread):
    def __init__(self, func, args, name = ''):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args
    
    #这样很巧妙,若func有返回值的话,可以调用此函数获取
    def getResult(self):
        return self.res

    def run(self):
        print 'starting', self.name, 'at', ctime()
        self.res = self.func(*self.args)
        print self.name, 'finished at', ctime()

threading中获取进程属性相关函数:

activeCount():当前活动的Thread对象个数

currentThread():返回当前Thread对象

enumerate():返回当前活动的Thread对象列表

settrace(func):为所有线程设置trace函数

setprofile(func):为所有线程设置profile函数

stack_size(size=0):返回新创建进程的栈大小,或者为后续线程设置栈大小为size

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值