zoukankan      html  css  js  c++  java
  • python中threading多线程

    python中有两个处理多线程的模块thread和threading。其中thread提供了多线程底层支持的模块,以低级原始的发那个是来处理和控制线程,使用起来较为复杂;而threading基于thread进行包装,将线程操作对象化。

    最基础的的多线程

    我们先看一个最最基础的多线程例子

    import threading
    import time
    class test(threading.Thread):
        def __init__(self,name,delay):
            threading.Thread.__init__(self)
            self.name = name
            self.delay = delay
    
        def run(self):
            print "%s is running"%self.name
            for x in range(self.delay):
               time.sleep(1)
               print "%s is saying hello %d"%(self.name,x)
    
    
    def main():
        t1 = test('Thread 1',3)
        t2 = test('Thread 2',2)
        t1.start()
        t2.start()
    
    
    if __name__ == '__main__':
        main()
        print "End of main"

    输出结果如下:

    Thread 1 is running
     End of mainThread 2 is running

    Thread 1 is saying hello 0
    Thread 2 is saying hello 0
    Thread 1 is saying hello 1
    Thread 2 is saying hello 1
    Thread 1 is saying hello 2

    可以看出Thread1 和Thread2基本上轮流执行的,这就是多线程的好处,否则如果顺序执行2个程序会需要2倍的时间。

    start是对thread的run()的封装,在调用start()的时候,会执行run()函数。

    如果把代码中的一段改成下面这样呢?

    def main():
        t1 = test('Thread 1',3)
        t2 = test('Thread 2',2)
        t1.start()
        print "wait for thread1 end"
        t1.join()
        t2.start()

    输出结果为:

    wait for thread1 endThread 1 is running

    Thread 1 is saying hello 0
    Thread 1 is saying hello 1
    Thread 1 is saying hello 2
    End of mainThread 2 is running

    Thread 2 is saying hello 0
    Thread 2 is saying hello 1

    从上面可以看出,调用了t1.join()后,t2会一直等到t1执行完毕才会开始执行。

    使用Queue进行多线程编程

    使用线程队列

    如前所述,当多个线程需要共享数据或者资源的时候,可能会使得线程的使用变得复杂。线程模 块提供了许多同步原语,包括信号量、条件变量、事件和锁。当这些选项存在时,最佳实践是转而关注于使用队列。相比较而言,队列更容易处理,并且可以使得线 程编程更加安全,因为它们能够有效地传送单个线程对资源的所有访问,并支持更加清晰的、可读性更强的设计模式。

    import threading
    import time
    import Queue
    import urllib2
    import os
    class test(threading.Thread):
        def __init__(self,queue):
            threading.Thread.__init__(self)
            self.queue = queue
    
        def run(self):
            while 1:
                url = self.queue.get()
                print self.name+"begin download"+url+"..."
                self.download(url)
                self.queue.task_done()
                print self.name+"download completed"
    
        def download(self,url):
            urlHandle = urllib2.urlopen(url)
            with open(os.path.basename(url)+".html","wb")as fp:
                while 1:
                    contents=urlHandle.read(1024)
                    if not contents:
                        break
                    else:
                        fp.write(contents)
    def main():
        ulrs = ["http://wiki.python.org/moin/Webprograming",
        "https://www.baidu.com",
        "http://wiki.python.org/moin/Documendation"]
    
        q = Queue.Queue(5)
        for each in ulrs:
          q.put(each)
    
        for i in range(5):
            t = test(q)
            t.setDaemon(True)
            t.start()
    
        q.join()
    
    
    if __name__ == '__main__':
        main()

     join()
    保持阻塞状态,直到处理了队列中的所有项目为止。在将一个项目添加到该队列时,未完成的任务的总数就会增加。当使用者线程调用 task_done() 以表示检索了该项目、并完成了所有的工作时,那么未完成的任务的总数就会减少。当未完成的任务的总数减少到零时,join() 就会结束阻塞状态。

    每个线程运行的时候就从队列里get一个url,这时候队列的长度就缩小1,然后完成的时候发送通知。直到队列为空的时候表示全部执行完毕。

    调试的时候发现即使不要task_done()也可以得到一样的结果。但是主线程会一直阻塞着无法继续执行,所以task_done的任务是告诉主线程的当前任务完成了,并递减未完成的任务数,这样主线程才知道什么时候所有的任务都完成了,好继续执行。

    使用线程池

    可以自己实现一个线程池模块,也可以用已经存在的第三方线程池库,本文用的是后者,比较简单。

    首先安装一个threadpool的库

    pip install threadpool

    然后用下面的代码完成和使用Queue一样的功能

    import urllib2
    import os
    import threadpool
    
    def download(url):
        urlHandle = urllib2.urlopen(url)
        with open(os.path.basename(url)+".html","wb")as fp:
            while 1:
                contents=urlHandle.read(1024)
                if not contents:
                    break
                else:
                    fp.write(contents)
    
    def main():
        ulrs = ["http://wiki.python.org/moin/Webprograming",
        "https://www.baidu.com",
        "http://wiki.python.org/moin/Documendation"]
        thread_num=5
        pool = threadpool.ThreadPool(thread_num)
        requests = threadpool.makeRequests(download,ulrs)
        print "put all request to thread pool"
        for each in requests:
            pool.putRequest(each)
        pool.poll()  # 处理任务队列中新的请求
        pool.wait()  # 阻塞用于等待所有执行结果
        print "destroy all threads"
        pool.dismissWorkers(thread_num,do_join=True)
    
    if __name__ == '__main__':
        main()
  • 相关阅读:
    68
    56
    Django manager 命令笔记
    Django 执行 manage 命令方式
    Django 连接 Mysql (8.0.16) 失败
    Python django 安装 mysqlclient 失败
    H.264 SODB RBSP EBSP的区别
    FFmpeg—— Bitstream Filters 作用
    MySQL 远程连接问题 (Windows Server)
    MySQL 笔记
  • 原文地址:https://www.cnblogs.com/streakingBird/p/4046102.html
Copyright © 2011-2022 走看看