python中的多线程

进程和线程简介

进程

进程简单来说就是计算机中正在执行的程序,每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据。进程由计算机上的操作系统来管理执行,分配时间。进程之间共享信息并不是十分轻松,因为每个进程之间都是相互独立的,它们使用IPC这种方式共享信息。

线程

线程是在同一个进程下执行的,信息可以很方便的在此进程和其下的线程中共享。因为线程一般并发执行,所以可以多个任务共同执行,减少程序的运行速度。这种并发其实是一种伪并发,计算机中并不能实现真正的同时执行,这种并发的实现机制其实是当一个线程运行短暂的时间后,让步下一个待运行的线程,自身重新去排队等待。因为这种机制,线程的并发执行在没有约束的情况下是有风险的,因为数据共享,线程之间可能会发生竞争,打个比方,a线程需要修改共享数据,b线程需要输出数据,ab线程并发执行,在没有约束的条件下,可能造成的结果是,b线程输出的数据可能一部分是修改前的,一部分是修改之后的,这样,不管我们是需要b线程输出修改前的数据,还是修改后的数据,都不能达成我们的要求,这样的情况下,我们必须对线程的并发进行一些约束,具体约束的方法后面我们将会说到。

python中的多线程

适用类型

python代码的执行由python虚拟机控制,而对虚拟机的控制是由全局解释器锁,GIL,控制的。对于面向I/O的python程序来说,GIL在I/O调用前被释放,以允许其他线程在I/O执行的时候运行。而对于I/O较少的程序来说,更倾向于在整段时间内占有处理器。简单来说,python多线程适用于那些I/O密集的程序使用

实现

python中实现多线程主要使用_thread模块(python2中为thread模块)、threading模块以及queue模块。

_thread

此模块不做过多介绍,因为一般推荐使用更高级的threading,在此主要介绍一些_thread模块的缺点,让大家明白为什么不推荐使用_threading。
1. threading相比于_thread模块来说更加高级,而_thread模块中的一些属性和threading模块有冲突。
2. _thread模块只拥有一个同步原语,而threading模块则拥有很多。
3. 在_thread模块中,主线程结束时,其他的线程也将强制性的结束

不过,也不要因此觉得_thread模块就需要被淘汰了,它只是不适用于我们这些简单的只是使用多线程的人,那些想访问线程更低层的专家多使用_thread模块来进行运作

threading

threading模块的Thread类是重要的执行对象

thr = threading.Tread(target=***,args=***)

target属性传入的是函数名称,args传入的是target中传入的函数需要的信息,是一个元组,如果没有待传入的信息,则输入一个空元组。
下面是一个创建threading实例的一个程序实例

import threading
from time import sleep,ctime

loops = [4,2]

def loop(nloop,nsec):
    print('start loop '+str(nloop)+' at : '+str(ctime()))
    sleep(nsec)
    print('loop ',nloop,' done at : ',ctime())

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

    for i in nloops:
        t = threading.Thread(target=loop,args=(i,loops[i]))
        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 threading
from time import sleep,ctime
lock = threading.Lock()
loops = [4,2]

def loop(nloop,nsec):
    lock.acquire()
    print('start loop '+str(nloop)+' at : '+str(ctime()))
    lock.release()
    sleep(nsec)
    print('loop ',nloop,' done at : ',ctime())

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

    for i in nloops:
        t = threading.Thread(target=loop,args=(i,loops[i]))
        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()

运行结果如下
这里写图片描述
可以看到,之前的问题被解决了
python2.5之后的版本中,还可以使用with语句来使用锁,进一步简化代码

from __future__ import with_statement 
import threading
from time import sleep,ctime

lock = threading.Lock()
loops = [4,2]

def loop(nloop,nsec):
    with(lock):
        #lock.acquire()
        print('start loop '+str(nloop)+' at : '+str(ctime()))
        #lock.release()
    sleep(nsec)
    print('loop ',nloop,' done at : ',ctime())

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

    for i in nloops:
        t = threading.Thread(target=loop,args=(i,loops[i]))
        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()

注意,语句from __future__ import with_statement要放在程序的最开头,不然会报错:from future imports must occurat the beginning of the file

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值