• 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()
  • 相关阅读:
    AT5147[AGC036D]Negative Cycle【dp,模型转换】
    pjudge#21652[PR #4]到底有没有九【数位dp】
    legion:使用多工具分门别类地扫描多个目标,有用
    antix
    skipfish: web scaner, usefully
    dmitry
    maltego
    常见靶场
    reconng从多个源头搜集主机和域名,但需要apikey。不大好用
    account/username&password tool
  • 原文地址:https://www.cnblogs.com/streakingBird/p/4046102.html
Copyright © 2020-2023  润新知