python多线程

来源:互联网 发布:监听2121端口 编辑:程序博客网 时间:2024/06/05 19:09

上回使用情况用到了线程,那时候直接copy别人的代码,然后针对自己问题改了下代码。今天有空学习下python的线程。
发现参考的博客:http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html

文章绝大部分内容来自:
《Python参考手册 第4版》:https://item.jd.com/12052200.html

在linux中的线程就是进程中的一个执行单元,可在进程中开多个线程。线程之间的资源可以共享。

  使用多个线程时,主机操作系统主要负责安排他们工作。做法:给每个线程分配一个小的时间片,并在素有活动任务之间快速循环–给每个任务分配一部分可用的cpu周期。如:同时允许的10个活动线程,操作系统将给每个线程分配大约1/10的cpu时间,同时在线程之间快速循环。
  但是如果有多个线程访问操作同一份资源呢?比方都将数据添加到文件中,而且也会删除其中部分数据,这就涉及到锁机制。


关于GIL的详细来历,请跳转这篇文章:
http://python.jobbole.com/81822/
从该文中得出的结论是,放弃多线程改用多进程。

但是多线程也有一定的适用场景:关键时候,那个解决问题用那个。
threading模块:提供Thread类和各种同步原语,用于多线程的程序。

Thread类用于表示单独的控制线程,下面可以创建一个线程:Thread(group=None,target=None,name=None,args=(),kwargs{})    group=None ,为以后版本保留的    target是一个可调用对象,线程启动时,run()方法将调用此对象,它的默认值是None,表示不调用任何对象。    name是线程名称。默认将创建一个“Thread-N”格式的唯一名称。    args是传递给target给target函数的参数元组。    kwargs是传递给target的关键字参数的字典。所以创建一个实例:+++++++++++++++++++import threadingdef printName():    passt = threading.Thread(target=printName,args=('hexian',))++++++++++++++上面的只是一个简单的测试。

一旦创建了Thread的实例,它支持下面的方法和属性:

t.start():    通过在一个单独的控制线程中调用run方法,启动线程。此方法只能调用一次。t.run():    线程启动时将调用此方法。默认,它将调用传递到调用函数中的目标函数。可以使用继承Thread的子类中重写该方法t.join([timeout])    等待直到线程终止或者出现超时为止。timeout为浮点数,单位秒。线程启动之前,不能调用它。t.is_alive():    判断线程是否活动,返回True或False.线程从start()开始,到run()结束之前都是活动的。t.isalive()该方法别名。t.name:    属性,线程名称,线程名为唯一标识符。t.ident:    属性,整数线程标识符。如果线程尚未启动,它的值为None.t.daemon:    线程的布尔型后台标识。必须在调用start()方法之前设置这个标识,它的初始值从创建线程的后台状态继承而来。

如下面:

[root@VM_131_54_centos allTest]# cat th1.py import threadingimport timedef clockTime(interval):    x = 1    while x:        print "The time is %s"%time.ctime()        time.sleep(interval)        x = 0t = threading.Thread(target=clockTime,args=(50,))t.daemon = Truet.start()print t.identprint t.name[root@VM_131_54_centos allTest]# python th1.py The time is Wed Oct 18 00:20:03 2017140491998664448Thread-1#当这种并不能出现sleep(50)的效果,这是因为t.daemon = True.一旦设置为True,线程则永远在后台运行。设置daemon标志会使在主程序退出后立即退出。线程自然销毁。

而下面一种:

[root@VM_131_54_centos allTest]# cat th2.py import threadingimport timedef clockTime(interval):        x = 1    while x:        print "The time is %s"%time.ctime()        time.sleep(interval)                x = 0t = threading.Thread(target=clockTime,args=(50,))t.daemon = Truet.start()[root@VM_131_54_centos allTest]# python th2.py The time is Wed Oct 18 00:35:13 2017[root@VM_131_54_centos allTest]# cat th1.py import threadingimport timedef clockTime(interval):        x = 1    while True:        print "The time is %s"%time.ctime()        time.sleep(interval)        x = 0t = threading.Thread(target=clockTime,args=(50,))t.start()print t.identprint t.name#这一种的结果就是:执行后等待50后结束。

一般使用的时候会将一个线程定义一个类:

[root@VM_131_54_centos allTest]# cat th3.py import threadingimport  timeclass ClockThread(threading.Thread):    def __init__(self,interval):        threading.Thread.__init__(self)        self.interval = interval    def run(self):        x = 1        while x:            print "the time is %s"%time.ctime()            time.sleep(self.interval)            x = 0t = ClockThread(15)t.start()#等待15秒。


Timer对象:

Timer: 隔一定时间调用一个函数,如果想实现每隔一段时间就调用一个函数的话,就要在Timer调用的函数中,再次设置Timer。Timer是Thread的一个派生类

Timer(interval,func[,args[,kwargs]])    创建定时器对象后,在过去interval时间后,执行函数func.在调用start()方法后会启动定时器。方法:t.start()t.cancel()  如果函数尚未执行,取消定时器。


Lock对象

互斥锁定,状态有两种,已锁定和未锁定。两个方法acquire()和release()用于修改锁定的状态。如果状态为锁定,尝试获取锁定将被阻塞,直到锁定被释放。如果有多个线程等待获取锁定,当锁定被释放时,只有一个线程能获取它。
注意:等待线程获取锁定的顺序没有定义。

使用下面的构造函数可以创建新的Lock实例lk = Lock()  创建新的Lock对象,初始化为未锁定Lock实例支持以下方法:lk.acquire([blocking])  获取锁定,如果有必要,需要阻塞到获取锁定释放为止。如果提供blocking参数并将它设为False,当无法获取锁定时立即返回False,如果成功获取锁定返回True.lk.release()  释放一个锁定。当锁定处于未锁定状态时,或者从与原本调用acquire()方法的线程不同的线程调用此方法,将出现错误。

RLock:可重入锁定

类似Lock,但是可以在内部可以执行嵌套acquire()和release()操作。


信号量与有边界的信号量。

信号量是一个基于计数器的同步原语。每次调用acquire()方法时此计数器减1,每次调用release方法时此计数器加1。如果计数器为0,acquire()方法将会阻塞,直到其他线程调用release()方法为止。

Semaphore([value])  创建一个新的信号量。value是计数器的初始值。如果省略此参数,计数器的值将被置1。s = Semaphore()s.acquire([blocking]) 获取信号量,如果进入时内部计数器大于0,此方法将它减1,然后立即返回。如果为0,阻塞,直到另一线程release()。s.release()BoundedSemaphore([value]):创建新的信号机。value为计数器的初始值。默认为1

信号机和互斥锁之间的差别:信号机能发信号。例如:可以从不同线程调用acquire()和release()方法,以便在生产者和使用者线程之间进行通信。

事件

事件用于线程之间通信。一个线程发出“事件”信号,一个或多个其他线程等待它。
+++++++++++++++++++++更新+++++++++++++
Threading模块:

这里写图片描述

thread类的实例方法:
这里写图片描述

守护线程

守护线程:一旦这是某一线程为守护线程,那么该线程不重要,如果你的进程要结束了,不用等待这个线程退出。

直接附上来源链接:
http://blog.csdn.net/u012063703/article/details/51601579

import timeimport threadingdef fun():    print "start fun"    time.sleep(2)    print "end fun"print "main thread"t1 = threading.Thread(target=fun,args=())t1.setDaemon(True)t1.start()time.sleep(1)print "main thread end"

线程锁

构造方法:
Lock()

实例方法:
acquire([timeout]): 使线程进入同步阻塞状态,尝试获得锁定。
release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

from time import sleep, ctimeimport threadingimport threadingimport randomthreads = []loops = [2,10]t = []mutex = threading.Lock()class MyThread(threading.Thread):    def __init__(self):        threading.Thread.__init__(self)    def run(self):        global t,mutex        if mutex.acquire():            a = int(random.random()*10)            if a not  in t and len(t) <=10:                t.append(a)                print t                mutex.release()            else:                print t                mutex.release() def test():    for x in range(10):        t = MyThread()        threads.append(t)    for x in range(len(threads)):        threads[x].start()    for x in range(10):        print threads[x].isAlive()if __name__ == "__main__":    test()

输出结果:

[root@VM_131_54_centos pachong]# python threadtest.py [9][9, 8][9, 8, 3][9, 8, 3][9, 8, 3, 2][9, 8, 3, 2][9, 8, 3, 2, 6][9, 8, 3, 2, 6][9, 8, 3, 2, 6][9, 8, 3, 2, 6]FalseFalseFalseFalseFalseFalseFalseFalseFalseFalse

待完善。。。。。