zoukankan      html  css  js  c++  java
  • 多线程应用-函数方式(thread)

    多线程只能使用一颗CPU,无法发挥多核心的优势。计算密集型用python的多线程效果不明显的,I/O密集型才能看出效果,可以发挥多核优势。

    GIL是全局资源锁,所以,如果没有涉及到资源的调用,是不会体现的。另外,如果线程进行的是简单运算,由于运算速度太快,导致线程间请求和释放GIL间隔太短,所以也不能观察到多核CPU跑满的情况。

    实例一:多线程ping,默认无法控制线程数量

    # -*- coding: UTF-8 -*-
    import time,threading,datetime
    from time import ctime,sleep
    import subprocess,sys
    reload(sys)
    
    #定义ping函数
    def fping(ip):
        sc = subprocess.Popen(['ping.exe',ip,'-n','2'],shell=True,stdout=subprocess.PIPE)
        ls=[]
        while sc.poll() == None:
            sclines = sc.stdout.readlines()
            for l in sclines:
                ls.append(l.strip().decode('GBK')+'
    ')
        #将ls转换为字符串格式,否则在输出的时候每个ping结果会串行        
        lss=''.join(ls)
        print lss
    
    #fping('192.168.200.250')
    
    stime=datetime.datetime.now()
    
    if __name__ =='__main__':
        ips=['www.baidu.com','www.163.com','www.sohu.com','www.cctv.com','www.xin.com','apollo.youxinpai.com']
        threads=[]
        for ip in ips:
            #创建并启动进程
            t = threading.Thread(target=fping,args=(ip,))
            #将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去
            t.setDaemon(True)
            t.start()
            threads.append(t)
        #等待每个线程结束   
        for t in threads:
            print t.name,t.is_alive(),ctime()
            t.join()
    
    etime=datetime.datetime.now()
    print (etime-stime).seconds,'s'

     

    多线程数量控制(直接控制可以同时启动的线程数量,起来后同时运行,不再控制):

    #定义分段函数,变相实现控制线程数量
    def lstg(num,lst):
    #定义每段的个数num
        l = len(lst)
        #取分成几组
        g = l/num
        #判断是否有剩余的数
        last = l%num
        lstn = []
        if num >= l:
            lstn.append(lst)
        else:
            for i in range(g):
                i=i+1
                n=i*num
                m=n-num 
                lstn.append(lst[m:n])
    
            if  last <> 0:
                lstn.append(lst[-last:])
        return lstn
    
    #定义ping函数
    def fping(ip):
        sc = subprocess.Popen(['ping.exe',ip,'-n','2'],shell=True,stdout=subprocess.PIPE)
        ls=[]
        while sc.poll() == None:
            sclines = sc.stdout.readlines()
            for l in sclines:
                ls.append(l.strip().decode('GBK')+'
    ')
        #将ls转换为字符串格式,否则在输出的时候每个ping结果会串行        
        lss=''.join(ls)
        print lss
    
    #fping('192.168.200.250')
    
    stime=datetime.datetime.now()
    
    if __name__ =='__main__':
        #定义线程数量
        tnum = 3
        ips=['www.baidu.com','www.163.com','www.sohu.com','www.cctv.com','www.xin.com','apollo.youxinpai.com','www.cmr.com.cn']
        for ips in lstg(tnum,ips):
            threads=[]
            for ip in ips:
                #创建并启动进程
                t = threading.Thread(target=fping,args=(ip,))
                #t.setName('th-'+ ip)
                t.setDaemon(True)
                t.start()
                threads.append(t)
            #等待每个线程结束   
            for t in threads:
                #print t.name,t.is_alive(),ctime()
                t.join()
    
    
    etime=datetime.datetime.now()
    print (etime-stime).seconds,'s'

    多线程数量控制(同时启动N个,限制同时可运行的线程数量):

    import threading
    def query(tnum,mutex,fp):
        with tnum: #限制同时运行的线程数量
            print fp,threading.currentThread()
            time.sleep(2)
    
    
    if __name__ == '__main__':
        threads=[]
        mutex=threading.Lock()
        tnum=threading.Semaphore(5) #定义同时可运行的线程数量为5
        files = range(10)
        for filepath in files:
            t = threading.Thread(target=query,args=(tnum,mutex,filepath))
            t.setDaemon(True)
            t.start() #同时启动线程数量不限
            #print t.name
            threads.append(t)
        for t in threads:
            t.join()

    线程未加锁:

    # -*- coding: UTF-8 -*-
    from time import ctime,sleep
    import threading,datetime
    
    def fun(mutex,arg1,ts):
        global a1
        a1=0
        a1=arg1+a1
        print str(a1)+ ' ' + ctime()
        sleep(ts)
    
        
    if __name__ == '__main__':
        arg1=2
        ts=1
        
        print datetime.datetime.now()
    
        mutex = threading.Lock()
        threads = []
        for arg1 in range(5):
    
            t = threading.Thread(target=fun,args=(mutex,arg1,ts))
    
            t.setDaemon(True)
            t.start()
            threads.append(t)
        for t in threads:
            t.join()
        print a1
    a1返回结果为:4

    线程加锁:

    # -*- coding: UTF-8 -*-
    from time import ctime,sleep
    import threading,datetime
    
    def fun(mutex,arg1,ts):
        global a1
        a1=0
        if mutex.acquire(1):    #加锁。锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理
            a1=arg1+a1
            print str(a1)+ ' ' + ctime()
            sleep(ts)
            mutex.release() #释放锁
            #print mutex.locked() #判断锁是否还在
        
        
    if __name__ == '__main__':
        arg1=2
        ts=1    
        print datetime.datetime.now()
    
        mutex = threading.Lock() #创建锁
        threads = []
        for arg1 in range(5):
            t = threading.Thread(target=fun,args=(mutex,arg1,ts))
            t.setDaemon(True)
            t.start()
            threads.append(t)
        for t in threads:
            t.join()
        print a1
    a1返回结果为10

     线程锁:http://www.cnblogs.com/tqsummer/archive/2011/01/25/1944771.html

    threading.Thread类

    这个类表示在单独的控制线程中运行的活动。有两种方法可以指定这种活动,给构造函数传递回调对象,或者在子类中重写run() 方法。其他方法(除了构造函数)都不应在子类中被重写。换句话说,在子类中只有__init__()run()方法被重写。

    一旦线程对象被创建,它的活动需要通过调用线程的start()方法来启动。这方法再调用控制线程中的run方法。

    一旦线程被激活,则这线程被认为是'alive'(活动)。当它的run()方法终止时-正常退出或抛出未处理的异常,则活动状态停止。isAlive()方法测试线程是否是活动的。

    一个线程能调用别的线程的join()方法。这将阻塞调用线程,直到拥有join()方法的线程的调用终止。

    线程有名字。名字能传给构造函数,通过setName()方法设置,用getName()方法获取。

    线程能被标识为'daemon thread'(守护线程).这标志的特点是当剩下的全是守护线程时,则Python程序退出。它的初始值继承于创建线程。这标志用setDaemon()方法设置,用isDaemon()获取。

    存在'main thread'(主线程),它对应于Python程序的初始控制线程。它不是后台线程。

    有可能存在'dummy thread objects'(哑线程对象)被创建。这些线程对应于'alien threads'(外部线程),它们在Python的线程模型之外被启动,像直接从C语言代码中启动。哑线程对象只有有限的功能,它们总是被认为是活动的,守护线程,不能使用join()方法。它们从不能被删除,既然它无法监测到外部线程的中止。

    class Thread(group=None, target=None, name=None, args=(), kwargs={})

    构造函数能带有关键字参数被调用。这些参数是:

    group 应当为 None,为将来实现ThreadGroup类的扩展而保留。

    target 是被 run()方法调用的回调对象. 默认应为None, 意味着没有对象被调用。

    name 为线程名字。默认,形式为'Thread-N'的唯一的名字被创建,其中N 是比较小的十进制数。

    args是目标调用参数的tuple,默认为()。

    kwargs是目标调用的参数的关键字dictionary,默认为{}。

    如果子线程重写了构造函数,它应保证调用基类的构造函数(Thread.__init__()),在线程中进行其他工作之前。

    start()
    启动线程活动。

    在每个线程对象中最多被调用一次。它安排对象的run() 被调用在一单独的控制线程中。

    run()

    用以表示线程活动的方法。

    你可能在子类重写这方法。标准的 run()方法调用作为target传递给对象构造函数的回调对象。如果存在参数,一系列关键字参数从argskwargs参数相应地起作用。

    join([timeout])
    等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。

    timeout参数未被设置或者不是None,它应当是浮点数指明以秒计的操作超时值。因为join()总是返回None,你必须调用isAlive()来判别超时是否发生。

    timeout 参数没有被指定或者是None时,操作将被阻塞直至线程中止。

    线程能被join()许多次。

    线程不能调用自身的join(),因为这将会引起死锁。

    在线程启动之前尝试调用join()会发生错误。

    getName()
    返回线程名。
    setName(name)
    设置线程名。

    这名字是只用来进行标识目的的字符串。它没有其他作用。多个线程可以取同一名字。最初的名字通过构造函数设置。

    isAlive()
    返回线程是否活动的。

    大致上,线程从 start()调用开始那点至它的run()方法中止返回时,都被认为是活动的。模块函数enumerate()返回活动线程的列表。

    isDaemon()
    返回线程的守护线程标志。
    setDaemon(daemonic)
    设置守护线程标志为布尔值daemonic。它必须在start()调用之前被调用。

    初始值继承至创建线程。

    当没有活动的非守护线程时,整个Python程序退出

  • 相关阅读:
    指向行数组指针和指针数组的区别
    安装文件在icinga上安装check_mk
    模式浏览器火狐、谷歌、IE关于document.body.scrollTop和document.documentElement.scrollTop 以及值为0的问题
    执行对象java面试题目2013/5/16
    属性序列化gson的@Expose注解和@SerializedName注解
    语言编译器编程语言分类及入门
    按钮实现Python绘图工具matplotlib的使用
    实现注册表网页超链接调用应用程序实现
    服务方法android如何保证service不被杀死
    函数日期mysql获取当天日期
  • 原文地址:https://www.cnblogs.com/dreamer-fish/p/5391432.html
Copyright © 2011-2022 走看看