zoukankan      html  css  js  c++  java
  • day32

    一、操作系统/应用程序

    a. 硬件
      - 硬盘
      - CPU
      - 主板
      - 显卡
      - 内存条
      - 电源
      ...
    b. 装系统(软件)
      - 系统就是一个由程序员写出来的软件, 该软件用于控制计算机的硬件, 让他们之间相互配合.
    c. 装软件(安装应用程序)
      - QQ
      - 百度云
      - pycharm
      ...

    二、并发和并行

    并发, 伪 由于执行速度特别快, 人感觉不到停顿
    并行, 真 创建10个人同时操作.

    并行:指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。
    并发:并发是指资源有限的情况下,两者交替轮流使用资源,比如一个单核cpu资源同时满足一个人使用,A用一会后,让给B,B用完继续给A,交替使用,目的是提高效率;

    并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。
    并发是从宏观上,在一个时间段上可以看成是同时执行的。

    三、线程/进程

    a. 单进程、 单线程的应用程序
    print('666')

    b. 到底什么是线程?什么是进程?
    Python自己没有这玩意,Python中调用的操作系统的线程和进程

    c. 单进程、多线程的应用程序

        import threading
        print('666')
    
        def func(arg):
            print(arg)
    
        t = threading.Thread(target=func)
        t.start()

    一个应用程序(软件),可以有多个进程(默认只有一个),一个进程中可以创建多个线程(默认一个)。

    d. 故事: Alex甄嬛西游传

    总结:
      1. 操作系统帮助开发者操作硬件。
      2. 程序员写好代码在操作系统上运行(依赖解释器)。
      3.当任务特别多,我们可以把以前的写法改进一下:

        import threading
        import requests
        import uuid
    
        url_list = [
    'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg', 'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg',
    'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg',
        ]
    
        def task(url):
            ret = requests.get(url)
            file_name = str(uuid.uuid4()) + '.jpg'
            with open(file_name, mode='wb') as f:
                f.write(ret.content)
    
        for url in url_list:
            task(url)
    
        """
        - 你写好代码
        - 交给解释器运行: python s1.py 
        - 解释器读取代码,再交给操作系统去执行,根据你的代码去选择创建多少个线程/进程去执行(单进程/单线程)。
        - 操作系统调用硬件:硬盘、cpu、网卡....
        """
    以前的我们写代码
        import threading
        import requests
        import uuid
        
        url_list = [
    'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg',
    'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg',
    'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg',
        ]
        
        
        def task(url):
            ret = requests.get(url)
            file_name = str(uuid.uuid4()) + '.jpg'
            with open(file_name, mode='wb') as f:
                f.write(ret.content)
        
        
        for url in url_list:
            t = threading.Thread(target=task, args=(url,))
            t.start()
        
        """
        - 你写好代码
        - 交给解释器运行: python s2.py 
        - 解释器读取代码,再交给操作系统去执行,根据你的代码去选择创建多少个线程/进程去执行(单进程/4线程)。
        - 操作系统调用硬件:硬盘、cpu、网卡....
        """
    现在的我们写代码

     四、Python中线程和进程(GIL锁)

    GIL锁(全局解释器锁): 用于限制一个进程中同一时刻只有一个线程被cpu调度。
    扩展:默认GIL锁再执行100个cpu指令(过期时间)切换线程。

        import sys
        
        v1 = sys.getcheckinterval()
        print(v1)  # 100
    查看方法

      问题1:为什么有这把GIL锁?
        python语言的创始人在开发这门语言时,目的是快速把语言开发出来,如果加上GIL锁(c语言加锁),切换时按照100条字节指令来进行线程间的切换。

      问题2:进程和线程的区别?
        线程,线程是cpu工作的最小单元;
        进程,进程是cpu资源分配的最小单元,为线程提供一个资源共享的空间;
        一个进程中可以有多个线程,一个进程中默认有一个主线程;
        对于python来说,它的进程和线程和其他语言有差异,有GIL锁。它保证一个进程中同一时刻只有一个线程被cpu调度;
        IO密集型操作可以使用多线程,计算密集型可以使用多进程;

      问题3:线程创建的越多越好吗?
        不是,线程之间进行切换,要做上下文管理。

    五、线程的使用

    1. 线程的基本使用

      import threading
      def func(arg):
          print(arg)
    
      t = threading.Thread(target=func,args=(11,)) # 创建一个子线程
      t.start()
    
      print(123)
      # 11
      # 123
      # 程序结束

    2.主线程默认等子线程执行完毕,才结束程序

        import threading
        import time
        def func(arg):
            time.sleep(arg)
            print(arg)
    
        t1 = threading.Thread(target=func,args=(3,))
        t1.start()
    
        t2 = threading.Thread(target=func,args=(9,))
        t2.start()
    
        print(123)
        
        # 3  # 程序开始3秒后
        # 6  # 程序开始6秒后
        # 程序结束

    3、主线程不再等,当主线程终止则所有子线程也终止,使用setDaemon(True)

        import threading
        import time
        def func(arg):
            time.sleep(2)
            print(arg)
        
        t1 = threading.Thread(target=func,args=(3,))
        t1.setDaemon(False)  # 主线程等待此子进程(默认是False等待)
        t1.start()
        
        t2 = threading.Thread(target=func,args=(9,))
        t2.setDaemon(True)  # 主线程等待此子进程(需要设置)
        t2.start()
        
        print(123)

    4、开发者可以控制主线程等待子线程(最多等待时间),使用join(n)

        import threading
        import time
        def func(arg):
            time.sleep(arg)
            print(arg)
        
        print("创建子线程t1")
        t1 = threading.Thread(target=func,args=(3,))
        t1.start()
        # 无参数: 让主线程在这里等着,直到子线程t1执行完毕,才可以往下走.
        # 有参数: 让主线程在这里最多等n秒,无论是否执行完毕,会继续往下走.
        t1.join(2)
        
        print("创建子线程t2")
        t2 = threading.Thread(target=func,args=(1,))
        t2.start()
        t2.join(3)  # 让主线程在这里等着,最多等待3秒,会继续往下走
    
        print(123)
        # 创建子线程t1
        # 创建子线程t2
        # 3
        # 1
        # 123
        # 程序结束

    5、线程名称

        import threading
        def func(arg):
            t = threading.current_thread()  # 获取当前执行该函数的线程的对象
            name = t.getName()  # 根据当前线程对象获取当前线程名称
            print(name, arg)
        
        t1 = threading.Thread(target=func,args=(11,))
        t1.setName('李白')
        t1.start()
        
        t2 = threading.Thread(target=func,args=(22,))
        t2.setName('白居易')
        t2.start()
        
        print(123)
        # 李白 11
        # 白居易 22
        # 123

    6、线程本质

       # 先打印:11?123?
        import threading
        def func(arg):
            print(arg)
    
        t1 = threading.Thread(target=func,args=(11,))
        t1.start()
        # start 是开始运行线程吗?不是
        # start 告诉cpu,我已经准备就绪,你可以调度我了。
        print(123)

    7、补充: 面向对象版本的多线程

        import threading
        def func(arg):
            print(arg)
    
        t1 = threading.Thread(target=func,args=(11,))
        t1.start()
    常见的创建多线程的方式
        import threading
        class MyThread(threading.Thread):
            def run(self):
                print(11111,self._args,self._kwargs)
    
        t1 = MyThread(args=(11,))
        t1.start()  # 在cpu内部,如果要调度这个线程的话会执行这个对象的run方法
    
        t2 = MyThread(args=(22,))
        t2.start()
    
        print('end')
        # 11111 (11,) {}
        # 11111 (22,) {}
        # end
    面对对象方式(一般不用,了解即可))

    六、Python中线程编写

    1. 计算密集型多线程无用

        impot threading
        v1 = [11, 22, 33]  # +1
        v2 = [44, 55, 66]  # +100
        
        def func(data, plus):
            for i in range(len(data)):
                data[i] = data[i] + plus
        
        t1 = threading.Thread(target=func,args=(v1,1))
        t1.start()
        
        t2 = threading.Thread(target=func,args=(v2,100))
        t2.start()

    2. IO操作,多线程有用

        import threading
        import requests
        import uuid
        
        url_list = [ 
      'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg',
      'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg',
      'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg', ] def task(url): ret = requests.get(url) file_name = str(uuid.uuid4()) + '.jpg' with open(file_name, mode='wb') as f: f.write(ret.content) for url in url_list: t = threading.Thread(target=task, args=(url,)) t.start()

    3. 多线程的问题(加锁和释放锁)

        import time
        import threading
        
        lock = threading.RLock()
        
        n = 10
        
        def task(i):
            print('这段代码不加锁',i)
        
            lock.acquire()  # 加锁,此区域代码同一时刻只能有一个线程执行
            global n
            print('当前线程',i,'读取到的n的值为: ',n)
            n = i
            time.sleep(1)
            print('当前线程',i,'修改的n的值为: ',n)
            lock.release()  # 释放锁
        
        for i in range(10):
            t = threading.Thread(target=task, args=(i,))
            t.start()

    总结:
      1. 应用程序/进程/线程的关系? *****(面试题: 进程/线程/协程的区别)
        工厂,厂房,工人, 工人共享厂房里的所有资源
        注意:线程是为了工作

      2. 为什么要创建线程?
        由于线程是cpu工作的最小单元,创建线程可以利用多核优势实现并行操作(Java/C#).

      3. 为什么要创建进程?
        进程和进程之间做数据隔离(Java/C#)
        注意:进程是为了提高环境让线程工作

      4. Python
        a. Python中存在一个GIL锁. *****
          - 造成: 多线程无法利用多核优势
          - 解决: 开多进程处理(浪费资源)
          进程和线程如何选择使用?
            IO密集型:多线程
            计算密集型:多进程
        b. 线程的创建
          - Thread    *****
          - MyTread
        c. 其他
          - join          *****
          - setDeanon   *****
          - setName      *****
          - threading.current_thread()   *****
        d. 锁
          - 加锁
          - 释放

  • 相关阅读:
    sql2slack alash3al 开源的又个轻量级工具
    pgspider fetchq 扩展docker镜像
    godns 集成coredns 的demo
    godns 简单dnsmasq 的dns 替换方案
    aviary.sh 一个基于bash的分布式配置管理工具
    使用coredns 的template plugin实现一个xip 服务
    nginx 代理 coredns dns 服务
    基于nginx proxy dns server
    几个不错的geodns server
    spring boot rest api 最好添加servlet.context-path
  • 原文地址:https://www.cnblogs.com/kangqi452/p/11762923.html
Copyright © 2011-2022 走看看