• 多线程多进程


    转自http://www.nnzhp.cn/archives/135

    一、线程&进程

    
    

    对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。进程是很多资源的集合。

    
    
    
    
    

    有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。

    
    

    由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。线程是最小的执行单元,而进程由至少一个线程组成。

    
    

    我们在做事情的时候,一个人做是比较慢的,如果多个人一起来做的话,就比较快了,程序也是一样的,我们想运行的速度快一点的话,就得使用多进程,或者多线程,在python里面,多线程被很多人诟病,为什么呢,因为Python的解释器使用了GIL的一个叫全局解释器锁,它不能利用多核CPU,只能运行在一个cpu上面,但是你在运行程序的时候,看起来好像还是在一起运行的,是因为操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。这个叫做上下文切换。

    
    

    二、多线程,python中的多线程使用theading模块

    
    

    下面是一个简单多线程

    
    
     1 import threading
     2     import time
     3     def sayhi(num): #定义每个线程要运行的函数
     4      
     5         print("running on number:%s" %num)
     6      
     7         time.sleep(3)
     8      
     9     if __name__ == '__main__':
    10         t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
    11         t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
    12         t1.start() #启动线程
    13         t2.start() #启动另一个线程
    多线程1
    
    

    下面是另一种启动多线程的方式,继承式

    import threading
        import time
        class MyThread(threading.Thread):
            def __init__(self,num):
                threading.Thread.__init__(self)
                self.num = num
         
            def run(self):#定义每个线程要运行的函数
         
                print("running on number:%s" %self.num)
        
                time.sleep(3)
         
        if __name__ == '__main__':
         
            t1 = MyThread(1)
            t2 = MyThread(2)
            t1.start()
            t2.start()
    多线程2

    这两种方式没有什么区别,两种写法而已,我个人喜欢用第一种,更简单一些。

    线程等待,多线程在运行的时候,每个线程都是独立运行的,不受其他的线程干扰,如果想在哪个线程运行完之后,再做其他操作的话,就得等待它完成,那怎么等待呢,使用join,等待线程结束

     1  import threading
     2             import time
     3             def run():
     4                 print('qqq')
     5                 time.sleep(1)
     6                 print('done!')
     7             lis = []
     8             for i in range(5):
     9                 t = threading.Thread(target=run)
    10                 lis.append(t)
    11                 t.start()
    12             for t in lis:
    13                 t.join()
    14             print('over')
    View Code

    守护线程,什么是守护线程呢,就相当于你是一个国王(非守护线程),然后你有很多仆人(守护线程),这些仆人都是为你服务的,一但你死了,那么你的仆人都给你陪葬。

     1 import threading
     2             import time
     3             def run():
     4                 print('qqq')
     5                 time.sleep(1)
     6                 print('done!')
     7             for i in range(5):
     8                 t = threading.Thread(target=run)
     9                 t.setDaemon(True)
    10                 t.start()
    11             print('over')
    View Code

     线程锁,线程锁就是,很多线程一起在操作一个数据的时候,可能会有问题,就要把这个数据加个锁,同一时间只能有一个线程操作这个数据

     1  import threading
     2         from threading import Lock
     3         num = 0
     4         lock = Lock()#申请一把锁
     5         def run():
     6             global num
     7             lock.acquire()#加锁
     8             num+=1
     9             lock.release()#解锁
    10         
    11         lis = []
    12         for i in range(5):
    13             t = threading.Thread(target=run)
    14             t.start()
    15             lis.append(t)
    16         for t in lis:
    17             t.join()
    18         print('over',num)
    线程锁

    下面来个简单的爬虫,看下多线程的效果

     1 import threading
     2         import requests,time
     3         urls  ={
     4             "baidu":'http://www.baidu.com',
     5             "blog":'http://www.nnzhp.cn',
     6             "besttest":'http://www.besttest.cn',
     7             "taobao":"http://www.taobao.com",
     8             "jd":"http://www.jd.com",
     9         }
    10         def run(name,url):
    11             res = requests.get(url)
    12             with open(name+'.html','w',encoding=res.encoding) as fw:
    13                 fw.write(res.text)
    14         
    15         
    16         start_time = time.time()
    17         lis = []
    18         for url in urls:
    19             t = threading.Thread(target=run,args=(url,urls[url]))
    20             t.start()
    21             lis.append(t)
    22         for t in lis:
    23             t.join()
    24         end_time = time.time()
    25         print('run time is %s'%(end_time-start_time))
    26         
    27         #下面是单线程的执行时间
    28         # start_time = time.time()
    29         # for url in urls:
    30         #     run(url,urls[url])
    31         # end_time = time.time()
    32         # print('run time is %s'%(end_time-start_time))
    View Code

    三、多进程,上面说了Python里面的多线程,是不能利用多核CPU的,如果想利用多核CPU的话,就得使用多进程,python中多进程使用multiprocessing模块

    1 from multiprocessing import Process
    2     import time
    3     def f(name):
    4         time.sleep(2)
    5         print('hello', name) 
    6     p = Process(target=f, args=('niu',))
    7     p.start()
    8     p.join()
    View Code

    四、进程池

    还可以使用进程池来快速启动几个进程,使用进程池的好处的就是他会自动管理进程数,咱们只需要给他设置一个最大的数就ok了。有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务

     1 from multiprocessing import Pool
     2 import os
     3  
     4  
     5 def worker(msg):
     6     print("%s开始执行,进程号为%d" %  (msg,os.getpid()))
     7  
     8 if __name__ == '__main__':
     9     
    10     po = Pool(3)  # 定义一个进程池,最大进程数3
    11     for i in range(0, 10):
    12         # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
    13         # 每次循环将会用空闲出来的子进程去调用目标
    14         po.apply_async(func=worker,args=(i,))
    15         #第一个func参数指定运行的函数,第二个args是参数,没有参数可以不写
    16     print("----start----")
    17     po.close()  # 关闭进程池,关闭后po不再接收新的请求
    18     po.join()  # 等待po中所有子进程执行完成,必须放在close语句之后
    19     print("-----end-----")
    View Code

    # 多线程、多进程
    # 1、线程是程序里面最小的执行单元
    # 2、进程是资源的集合
    # 线程是包含在一个进程里面的,一个进程可以有多个进程
    # 一个进程里面默认有一个线程
    # import threading,time
    #
    # def run():
    # time.sleep(3) #干活需要3S
    # print('哈哈哈')
    #
    # # for i in range(5): #串行
    # # run()
    #
    # for i in range(5): #并行
    # t=threading.Thread(target=run) #实例化了一个线程
    # t.start()
    #
    # # 多线程,就是N个线程一起在干活




    # urls = {
    # 'besttest':'http://www.besttest.cn',
    # 'niuniu':'http://www.nnzhp.cn',
    # 'dsx':'http://www.imdsx.cn',
    # 'cc':'http://www.cc-na.cn',
    # 'alin':'http://www.limlhome.cn'
    # }
    #
    #
    # import requests,threading,time
    # def down_html(file_name,url):
    # res=requests.get(url).content #content二进制的方式
    # open(file_name+'.html','wb').write(res) #wb二进制方式打开
    #
    #
    # # # 1、串行
    # # start_time=time.time()
    # # for k,v in urls.items():
    # # down_html(k,v)
    # # end_time=time.time()
    # #
    # # run_time=end_time-start_time
    # # print('下载共花了XX时间',run_time)
    #
    # # 2、并行
    # start_time=time.time()
    # for k,v in urls.items(): #5次
    # # 多线程的函数如果传参的话,必须得用args
    # t=threading.Thread(target=down_html,args=(k,v))
    # t.start()
    #
    # #共6个线程
    # #进程里面默认有一个线程,这个线程叫做主线程
    # end_time=time.time()
    # run_time=end_time-start_time
    # print('下载共花了XX时间',run_time)





    urls = {
    'XX1':'http://www.XXX.cn',
    'XX2':'http://www.XXX.cn',
    'XX3':'http://www.iXX.cn',
    'XX4':'http://www.XXa.cn',
    'XX5':'http://www.limlhome.cn'
    }


    import requests,threading,time
    data={}
    def down_html(file_name,url):
    start_time = time.time()
    res=requests.get(url).content #content二进制的方式
    open(file_name+'.html','wb').write(res) #wb二进制方式打开
    end_time = time.time()
    run_time = end_time - start_time
    # print(run_time,url) #看哪个url下载的时间最长
    data[url]=run_time

    # 1、串行
    # start_time=time.time()
    # for k,v in urls.items():
    # down_html(k,v)
    # end_time=time.time()
    #
    # run_time=end_time-start_time
    # print('下载共花了XX时间',run_time)


    # 2、并行
    threads=[]
    start_time=time.time()
    for k,v in urls.items(): #5次
    # 多线程的函数如果传参的话,必须得用args
    t=threading.Thread(target=down_html,args=(k,v))
    t.start()
    threads.append(t)

    for t in threads: #主线程循环等待5个子线程执行结束
    t.join()
    print(data)


    #共6个线程
    #进程里面默认有一个线程,这个线程叫做主线程
    end_time=time.time()
    run_time=end_time-start_time
    print('下载共花了XX时间',run_time)
  • 相关阅读:
    dynamic 类型不能访问属性
    chrome浏览器另存为/上传附件崩溃
    HTTP 错误 405.0
    2019目录之电影
    面向面试编程-概念之-分布式与集群的区别和联系
    面向面试编程代码片段之GC
    2018-12-24
    VUE iview date-picker取时间范围...
    关闭shift中英文切换 英文代码/中文注释随意切换着写。
    为什么你在群里提的技术问题没人回答?
  • 原文地址:https://www.cnblogs.com/jiadan/p/9120827.html
Copyright © 2020-2023  润新知