Python 多线程,ThreadLocal和线程锁

    Python多线程编程非常类似于linux C的pthread多线程库,只不过以面向对象的形式提供。Cpython 由于解释器实现策略的问题,增加了GIL(Global Interpreter Lock)全局解释器锁,使得python多线程在同一时刻只能有一个线程执行。因此,在使用Cpython时,对于CPU密集型任务,我们最好不采用python多线程方案,而是使用多进程方案。但对于IO密集型任务,由于每次进行IO的时候,python会释放GIL锁,多线程方案还是可取的。

    python的多线程是封装在threading模块中的,有两种方式编写多线程程序,一种是创建一个Thread对象,然后调用对象的start()方法,另一种是继承Thread类,然后重写run()方法。

    创建Thread类对象的示例代码如下:

import os, sys
import threading
import time

def my_thread(someone):
    print('[{}]: {} begin working'.format(threading.currentThread(), someone))
    time.sleep(2)
    print('[{}]: {} finished working'.format(threading.currentThread(), someone))


if __name__ == '__main__':
    t1 = threading.Thread(target = my_thread, args = ('Jack',))
    t2 = threading.Thread(target = my_thread, args = ('Edward',))

    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print('[%s] Main thread finished' % threading.currentThread())

运行结果:

[<Thread(Thread-1, started daemon 140397066352384)>]: Jack begin working
[<Thread(Thread-2, started daemon 140397057959680)>]: Edward begin working
[<Thread(Thread-1, started daemon 140397066352384)>]: Jack finished working
[<Thread(Thread-2, started daemon 140397057959680)>]: Edward finished working
[<_MainThread(MainThread, started 140397088982784)>] Main thread finished

    说明:setDaemon(True)方法使得调用线程(主线程)成为被调用线程(t1, t2)的守护线程,当调用线程(守护线程)退出时,子线程立马被回收。反之,setDaemon(False)(默认)情况下,调用线程退出是,子线程继续运行,直到自行退出。

                join()方法使得调用线程(主线程)阻塞,直到被调用线程(t1,t2)主动退出。

    继承Thread类示例代码如下:

import os, sys
import threading
import time

class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        print('[%s] begin' % threading.currentThread().getName())
        time.sleep(2)
        print('[%s] end' % threading.currentThread().getName())



if __name__ == '__main__':
    t1 = MyThread()
    t2 = MyThread()

    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print('[%s] Main thread finished' % threading.currentThread())

运行结果:

[Thread-1] begin
[Thread-2] begin
[Thread-1] end[Thread-2] end

[<_MainThread(MainThread, started 140297001658112)>] Main thread finished

 

    threading模块还提供了线程互斥锁threading.Lock和threading.RLock,并提供了acquire()和release()两个接口用于获取和释放锁,以Lock为例示例代码如下:

import os, sys
import threading
import time

a = 10
lock = threading.Lock()

def my_thread(*args):
    while True:
        lock.acquire()
        try:
            global a
            if args[0] == 1:
                a = 1
            elif args[0] == 2:
                a = 2
            print('[%s]: %d' % (threading.currentThread().getName(), a))
        finally:
            lock.release()


if __name__ == '__main__':
    t1 = threading.Thread(target = my_thread, args = (1,))
    t2 = threading.Thread(target = my_thread, args = (2,))

    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print('[%s] Main thread finished' % threading.currentThread())

    很多语言都提供了ThreadLocal(Java,C++)线程本地变量,python也不例外(threading.local)。我们知道,如果多个线程共享同一个对象属性,传统模式下,对该该属性的修改与访问需要加上线程互斥锁,比如 threading.Lock。但是互斥锁的系统开销比较大:锁定的资源同一时刻串行执行,线程切换开销。ThreadLocal通过给每个线程分配一个共享资源的副本,达到每线程资源独占的效果,从而避免了线程锁的开销,示例代码如下:

import os, sys
import threading
import time

a = threading.local()

def my_thread(*args):
    while True:
        if args[0] == 1:
            a = 1
        elif args[0] == 2:
            a = 2
        print('[%s]: %d' % (threading.currentThread().getName(), a))


if __name__ == '__main__':
    t1 = threading.Thread(target = my_thread, args = (1,))
    t2 = threading.Thread(target = my_thread, args = (2,))

    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print('[%s] Main thread finished' % threading.currentThread())

转载于:https://my.oschina.net/yepanl/blog/1586381

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值