zoukankan      html  css  js  c++  java
  • 多线程

    多线程
    1、线程是程序里面最小的执行单元。
    2、进程是资源的集合

    多线程就是多个线程一起干活,及并行运行
    1、传统方式:串行,循环5次需要15s
    import threading
    def run():
        time.sleep(3)#干活需要3秒
        print('哈哈哈哈哈')
    for i in range(5):#串行,就是一个一个输出
        run()
    #运行的时候可以看到每个三秒输出:哈哈哈哈哈

    2、并行:利用多线程并发,节省时间

    import  threading,time
    def run():
        time.sleep(3)#干活需要3秒
        print('哈哈哈哈哈')
    for i in range(5):#并行
        t=threading.Thread(target=run)#实例化一个线程,其中target=执行的函数名
      t.start() # #多线程,就是N个线程一起在干活 #结果,运行后三秒输出5个结果:哈哈哈哈哈哈

     例子:多线程爬虫,比较串行和并发的时间:

    (1)串行方式:

    import threading,time,requests
    urls = {
        'besttest':'http://www.besttest.cn',
        'niuniu':'http://www.nnzhp.cn',
        'dsx':'http://www.imdsx.cn',
        'cc':'http://www.cc-na.cn'}
    data={}#在线程中是获取不到返回值的,只能通过定义一个列表或者字典,将数据保存在列表或者字典中返回才能获取
    def down_html(filename,url):
        sart_time = time.time()#开始时间
        res=requests.get(url).content
        open(filename+'.html','wb').write(res)
        end_time = time.time()#结束时间
        run_time = end_time - sart_time
        data[url]=run_time#运行时间
        print(run_time,url)#打印每个下载文件的运行时间
    
    #1、用串行
    sart_time=time.time()#开始时间
    for k,v in urls.items():
        down_html(k,v)
    end_time=time.time()#结束时间
    run_time=end_time-sart_time#运行时间
    print('串行下载总共花了XXX时间',run_time)
    
    #结果
    0.33101892471313477 http://www.besttest.cn
    1.4620835781097412 http://www.nnzhp.cn
    0.9180524349212646 http://www.imdsx.cn
    3.6742103099823 http://www.cc-na.cn
    串行下载总共花了XXX时间 6.38536524772644

    2、并行方式:

    (1)一开始以为像串行一样直接在循环线程之前加开始时间,循环线程结束后加结束时间就能够计算到并行的运行时间,其实这样是错误的,究竟是为什么呢?看下面分析:

    因为在运行多线程时候,默认先会运行主线程,其他线程只是开始运行(下载网页)并不一定结束(而一个进程中的多个线程都是相互独立的。)主线程负责定义函数,启动其

    他线程等。因此,最终并行运行的结果时间,仅仅是主线程的运行时间。

    import threading,time,requests
    
    urls = {
        'besttest':'http://www.besttest.cn',
        'niuniu':'http://www.nnzhp.cn',
        'dsx':'http://www.imdsx.cn',
        'cc':'http://www.cc-na.cn'}
    
    def down_html(file_name,url):
        res = requests.get(url).content  #返回二进制内容
        open(file_name+'.html','wb').write(res)  #因此打开的时候,用wb二进制打开
    
    #用并行方式
    start_time = time.time()
    for k,v in urls.items():#因为urls里有3个Key,因此会启动3个线程
        t = threading.Thread(target=down_html,args=(k,v))  #使用多线程调用参数时,必须用args=xx才能传参
        t.start()
    end_time = time.time()
    run_time = end_time - start_time
    print('下载共花了%s时间'%run_time)
    
    #结果:
    下载共花了0.004000425338745117时间

     (2)那如何计算多线程的运行时间呢?接下来先讲一下线程等待:

    1、计算主线程时间,跟上述代码一样

    import  threading,time
    #主线程:默认有个主线程,主线程主要是启动子线程,启动之后跟子线程没有关系
    #上面计算的是主线程运行的时间,不是子线程的时间
    def run():
        time.sleep(3)
        print('哈哈哈哈')
    #1、主线程时间
    sart_time = time.time()
    for i in range(5):  # 并行
        t=threading.Thread(target=run)#实例化一个线程
        t.start()
    end_time=time.time()
    run_time=end_time-sart_time
    print('run_time',run_time)

    2、可以使用join()函数设置线程等待:

    t.join()放在线程循环体里面,主线程等待第一个线程结束才开始循环第二个线程,所以并没有进行并行,还是跟串行一样

    import  threading,time
    def run():
        time.sleep(3)
        print('哈哈哈哈')
    
    sart_time = time.time()
    for i in range(5):  # 并行
        t=threading.Thread(target=run)#实例化一个线程
        t.start()
        t.join()#来一个线程等待一个线程执行结束,等执行结束了才循环继续下一个线程执行结束,所以总共会等待15s,变成串行
    end_time=time.time()
    run_time=end_time-sart_time
    print('run_time',run_time)
    
    #结果
    哈哈哈哈
    哈哈哈哈
    哈哈哈哈
    哈哈哈哈
    哈哈哈哈
    run_time 15.000857830047607

    3、主线程等待5个线程完成:这就是多线程并行时间

    主线程负责启动5个子线程,把每个线程放在threads list里,然后等待所有线程等待完毕后,再执行end_time = time.time()语句,实现最后计算所有线程都结束的并发时间。

    import  threading,time
    def run():
        time.sleep(3)
        print('哈哈哈哈')
    sart_time = time.time()
    threads=[]
    for i in range(5):  # 并行
        t=threading.Thread(target=run)#实例化一个线程
        t.start()
        threads.append(t)
    for t in threads:#为什么循环,是因为循坏等待才能计算子线程的运行时间
        t.join()#循环等待,只主线程循坏等待5个子线程执行结束,及等5个线程执行完就行了
    end_time=time.time()
    run_time=end_time-sart_time
    print('run_time',run_time)
    #结果
    哈哈哈哈
    哈哈哈哈
    哈哈哈哈
    哈哈哈哈
    哈哈哈哈
    run_time 3.001171827316284

    4、计算上述爬虫的多线程执行时间,代码如下:

    import requests
    data={}#在线程中是获取不到返回值的,只能通过定义一个列表或者字典,将数据保存在列表或者字典中返回才能获取
    
    def down_html(filename,url):#计算每个线程的执行时间
        sart_time = time.time()
        res=requests.get(url).content
        open(filename+'.html','wb').write(res)
        end_time = time.time()
        run_time = end_time - sart_time
        data[url]=run_time
        print(run_time,url)
    
    #用并行
    sart_time=time.time()
    threads=[]
    for k,v in urls.items():#5次
        t=threading.Thread(target=down_html,args=(k,v))#多线程的函数如果传参数的话,必须用args
        t.start()
        threads.append(t)
    for t in threads:#为什么循环,是因为循坏等待才能计算子线程的运行时间
        t.join()
    end_time=time.time()
    run_time=end_time-sart_time
    print('并行下载总共花了XXX时间',run_time)
    #6个线程,进程里面默认有一个线程,这个线程叫做主线程
    
    #结果:
    0.37302136421203613 http://www.besttest.cn
    1.2510716915130615 http://www.imdsx.cn
    1.5230872631072998 http://www.nnzhp.cn
    3.583204746246338 http://www.cc-na.cn
    并行下载总共花了XXX时间 3.588205337524414

     线程锁

    import threading,time
    num=1
    lock=threading.Lock()#申请一把锁
    def run():
        time.sleep(1)
        global num
        lock.acquire()#加锁
        num+=1
        lock.release()#解锁
    ts=[]
    for i in range(50):
        t=threading.Thread(target=run)
        t.start()
        ts.append(t)
    [t.join() for t in ts]
    print(num)
    #锁的就是,在多个线程同时修改一个数据的时候,可能会把数据覆盖,在Python2里面需要加锁
    #Python3中里面不加锁也无所谓,默认会自动帮你加锁
  • 相关阅读:
    网络技术全方位解析之三:RAID
    Linux系统安全隐患及加强安全管理的方法
    Silverlight 程序架构
    (转载)Qt:给QLineEdit加上一个搜索按钮
    (转载)StarUML启动时候出现"System Error. Code:1722. RPC服务器不可用."错误的解决办法
    (转载)starUML connect elements exactly
    (转载)Qt:拖拽图片到QLabel上并显示
    (转载)Qt:禁止qDebug的输出
    (转载)葱的营养价值和食用功效
    (转载)Qwt的安装与使用
  • 原文地址:https://www.cnblogs.com/hwtfamily/p/9095176.html
Copyright © 2011-2022 走看看