python多线程

上回使用情况用到了线程,那时候直接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 threading
def printName():
    pass
t = 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 threading
import time
def clockTime(interval):
    x = 1
    while x:
        print "The time is %s"%time.ctime()
        time.sleep(interval)
        x = 0
t = threading.Thread(target=clockTime,args=(50,))
t.daemon = True
t.start()
print t.ident
print t.name

[root@VM_131_54_centos allTest]# python th1.py 
The time is Wed Oct 18 00:20:03 2017
140491998664448
Thread-1
#当这种并不能出现sleep(50)的效果,这是因为t.daemon = True.
一旦设置为True,线程则永远在后台运行。设置daemon标志会使在主程序退出后立即退出。线程自然销毁。

而下面一种:

[root@VM_131_54_centos allTest]# cat th2.py 
import threading
import time
def clockTime(interval):
        x = 1
    while x:
        print "The time is %s"%time.ctime()
        time.sleep(interval)
                x = 0
t = threading.Thread(target=clockTime,args=(50,))
t.daemon = True
t.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 threading
import time
def clockTime(interval):
        x = 1
    while True:
        print "The time is %s"%time.ctime()
        time.sleep(interval)
        x = 0
t = threading.Thread(target=clockTime,args=(50,))
t.start()
print t.ident
print t.name
#这一种的结果就是:执行后等待50后结束。

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

[root@VM_131_54_centos allTest]# cat th3.py 
import threading
import  time

class 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 = 0
t = 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 time
import threading


def 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, ctime
import threading
import threading
import random

threads = []
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]
False
False
False
False
False
False
False
False
False
False

待完善。。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值