• Day35 python基础--并发编程基础4


    一,进程的数据共享机制--Manager模块

      1.把所有实现了数据共享的比较便捷的类都重新封装了一遍

      2.并且在原有的multiprocessing的基础上,增加了新的机制list、dict

      3.支持的数据类型非常有限

      4.list、dict都不是数据安全的,需要自行加锁来保证数据安全

      5.工作中一般是通过第三方工具实现进程间的数据共享

    from multiprocessing import Manager,Process,Lock
    def work(d,lock):
        with lock:
        # lock.acquire()
            d['count'] -= 1      #操作数据是一个取值赋值过程
        # lock.release()
    
    if __name__ == '__main__':
        lock = Lock()
        m = Manager()      #with Manager() as m: 
        dic = m.dict({'count':100})
        p_1 = []
        for i in range(100):
            p = Process(target=work,args=(dic,lock))
            p_1.append(p)
            p.start()
        for p in p_1:
            p.join()
        print(dic)

    二,进程的回调函数

      1.当子进程执行完毕之后执行callback函数

      2.子进程的返回值会作为callback的参数

      3.回调函数在主进程执行

      应用场景:

        1.使用主进程统一的获取结果,这样的化在进程之间没有数据隔离

        2.多个子进程所做的事情是比较长时间的,而主进程中回调函数的执行速度都比较快

          子进程中做网络访问,主进程处理网页的结果

          子进程有大量的计算要去做,回调函数等待结果做简单处理

    def func(i):
        print('第一个任务',os.getpid())
        return '*'*i,
    def call_back(res):  #只能接受一个参数,可以*res;本体是args*,传多个参数会聚合为一个元组
       print('回调函数:',os.getpid()) 
      print('ret-->',res) if __name__ == '__main__': p = Pool()
       print('主进程:',os.getpid()) p.apply_async(func,args
    =(1,),callback=call_back) p.close() p.join()
    #实例一:
    url_lst = ['http://www.baidu.com',
               'http://www.souhu.com',
               'http://www.sogou.com',
               'http://www.4399.com',
               'http://www.cnblogs.com']
    import re
    from multiprocessing import Pool
    from urllib.request import urlopen
    
    def get_url(url):
        response = urlopen(url)
        ret = re.search('www.(.*?).com',url)
        print('%s finish'%ret.group(1))
        return ret.group(1),response.read()
    
    def call(content):
        url,con = content
        with open(url+'.html','wb') as f:
            f.write(con)
    
    if __name__ == '__main__':
        p = Pool()
        for url in url_lst:
            p.apply_async(get_url,args=(url,),callback=call)
        p.close()
        p.join()
    #实例二
    import re
    from multiprocessing import Pool
    from urllib.request import urlopen
    
    def get_url(url):
        response = urlopen(url)
        ret = re.search('www.(.*?).com',url)
        print('%s finish'%ret.group(1))
        return ret.group(1),response.read()
    
    def call(content):
        url,con = content
        with open(url+'.html','wb') as f:
            f.write(con)
    
    if __name__ == '__main__':
        p = Pool()
        p_lst = []
        for url in url_lst:
            ret = p.apply_async(get_url,args=(url,))  #ret是一个内存地址
            p_lst.append(ret)
        for ret in p_lst:
            call(ret.get())

    三,线程

      线程vs进程:

        进程的概念:

          1.计算机中最小的资源分配单位

          2.进程对于操作系统来说还是有一定负担的

          3.创建一个进程,操作系统要分配的资源大致有:

            代码,数据,文件

        线程的概念

          1.轻量级

          2.没有属于自己的进程资源

          3.为什么要有线程

               一条线程只负责执行代码,没有自己独立的代码,变量,文件资源

               解决高并发的情况下,资源有限的问题

          4.什么是线程:

            线程是计算机中被cpu调度的最小单位

            你的计算机当中的cpu都是执行的线程中的代码

          5.线程和进程之间的关系

            每一个进程中都有至少一条线程在工作

          6.线程的特点

            同一个进程中的所有线程的资源时共享的

            轻量级:没有自己的资源

          7.进程和线程之间的区别

            占用的资源,线程之间共享进程内的资源,但是线程内的局部变量还是要占用资源

            调度的效率:线程是计算机中被cpu调度的最小单位,调度速度快,开销小

            资源是否共享:线程共享进程内的资源

            可以并发执行

          8.通用问题

            java,c++,c#在一个进程中的多个线程能够并行

            为什么python(c)中一个进程中的多个线程不能并行?

              1.python是一个解释型的语言

              2.cpython解释器,内部有一把全局解释器(GIL)

                所以线程不能充分的利用多核

                同一时刻同一个进程中的线程只有一个能被cpu执行

              3.GIL锁:确实是限制了程序效率

              4.GIL目前是能够帮助你在线程的切换中提高效率

              5.asyncio模块

          9.python的劣势,关于GIL的历史遗留问题

            python不能实现,cpu利用率,极端的高计算型,需要多线程多核cpu高利用需求

            解决办法:多进程,换一个解释器

    #线程的代码实现:thread、threading
    #效率对比
    import os
    import time
    from threading import Thread
    from multiprocessing import Process
    def func(i):
        # time.sleep(1)
        print('子线程%s'%i,os.getpid())
    #多线程
    # print('主进程',os.getpid())
    if __name__ == '__main__':
        t_lst = []
        start = time.time()
        for i in range(100):
            t = Thread(target=func,args=(i,))
            t.start()
            t_lst.append(t)
        for t in t_lst:
            t.join()
        tt = time.time() - start
    
    # if __name__ == '__main__':
        start = time.time()
        p_lst = []
        for i in range(100):
            p = Process(target=func,args=(i,))
            p.start()
            p_lst.append(p)
        for p in p_lst:
            p.join()
        print(time.time() - start)
        print(tt)
    # 多线程的数据共享
    import os
    import time
    from threading import Thread
    from multiprocessing import Process
    num = 100
    def func():
        global num
        num -= 1
    
    if __name__ == '__main__':
        t_lst = []
        for i in range(100):
            t = Thread(target=func)
            t.start()
            t_lst.append(t)
        for t in t_lst:
            t.join()
        print(num)
    #守护线程
    #守护线程是在主线程结束之后,还等待了子线程执行结束才结束
    #主线程结束,意味着主进程结束
    #主线程等待所有的线程结束
    #主线程结束之后,守护线程随着主进程的结束自然结束了
    import time
    from threading import Thread
    def func1():
        while True:
            time.sleep(0.5)
            print(123)
    def func2():
        print('func2 start')
        time.sleep(3)
        print('func end')
    
    t1 = Thread(target=func1)
    t2 = Thread(target=func2)
    t1.setDaemon(True)
    t1.start()
    t2.start()
    print('主线程的代码结束')
    #Thread实例对象的方法
      # isAlive(): 返回线程是否活动的。
      # getName(): 返回线程名。
      # setName(): 设置线程名。
    
    threading模块提供的一些方法:
      # threading.currentThread(): 返回当前的线程变量。
      # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
      # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
    
    from threading import Thread
    import threading
    from multiprocessing import Process
    import os
    
    def work():
        import time
        time.sleep(3)
        print(threading.current_thread().getName())
    
    
    if __name__ == '__main__':
        #在主进程下开启线程
        t=Thread(target=work)
        t.start()
    
        print(threading.current_thread().getName())
        print(threading.current_thread()) #主线程
        print(threading.enumerate()) #连同主线程在内有两个运行的线程
        print(threading.active_count())
        print('主线程/主进程')
    
        '''
        打印结果:
        MainThread
        <_MainThread(MainThread, started 140735268892672)>
        [<_MainThread(MainThread, started 140735268892672)>, <Thread(Thread-1, started 123145307557888)>]
        主线程/主进程
        Thread-1
        '''

     四,总结

    #线程
    #线程和进程之间的关系
        #每个进程内都有一个线程
        #线程是不能独立存在的
    #线程和进程之间的区别
        #同一个进程中线程之间的数据是共享的
        #进程之间的数据是隔离的
        #线程是由cpu执行的最小单位
            #操作系统调度
        #进程是计算机中最小的资源分配单位
    #python
        #GIL锁 全局解释器锁 全局锁
        #锁线程:同一时刻同一进程只会有一个线程访问cpu
            #锁的是线程而不是数据
        #当程序是高IO形的 多线程
        #当程序是高计算(cpu)型 多进程
            #多进程数的范围:cpu*1 ~ cpu*2
    
    #threading
    #Thread
        #守护线程:主线程结束之后才结束
    
    #socketserver IO多路复用 + 多线程
    #框架 并发的效果:多线程,协程的概念 flask
    #爬虫:线程池 协程

          

          

  • 相关阅读:
    登录认证,全选,反选
    jQuery基础知识
    jQuery
    js练习
    BOM DOM
    mysql视图
    用CrwalSpider爬取boss直聘
    设置piplines.py数据管道
    在middlewares.py文件里添加代理ip
    爬取豆瓣电影
  • 原文地址:https://www.cnblogs.com/lianyeah/p/9692515.html
Copyright © 2020-2023  润新知