zoukankan      html  css  js  c++  java
  • Python ----- 线程和进程

      Python线程                                                                      

    1. 操作系统/应用程序

      操作系统分为: 硬件 , 装系统和安装软件

        硬件: 

          -- 硬盘

          -- CPU

          -- 主板

          -- 显卡

          -- 内存

          -- 电源

          .......

        装系统: 系统就是一个由程序员写出来的软件, 该软件用于控制计算机的硬件,让他们之间进行相互配合.

        安软件: 

          -- QQ

          -- 百度云

          .....

    2. 操作中的"并发"

      并发(伪) : 由于执行熟读特别快 , 感觉不到停顿 , 是由同一个CPU执行

      并行(真) : 创建多个线程同时操作

    3. Python中线程和进程

    print("111")
    单线程 , 单进程的简单程序

      Python中没有线程和进程 , 它调用的是操作系统的线程和进程 . 

    import threading
    
    def func(arg):
        print(arg)
    
    t = threading.Thread(target = func)
    t.start()
    
    print("end")
    单进程 , 多线程的程序

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

      总结 : 

        1. 操作系统帮助开发者操作硬件

        2. 程序员写好代码在操作系统上运行(解释器)

        Python多线程情况下 :

          -- 计算密集型操作 : 效率低(GIL锁)

          -- IO操作 : 效率高

        Python多进程的情况下 :

          -- 计算密集型操作 : 效率高(浪费资源)

          -- IO操作 : 效率高(浪费资源)

        写Python时 :

          IO密集型用多线程 : 文件/输入输出/socket网络通信

          计算密集型用多进程

        进程与线程的区别:

          线程 , CPU工作的最小单元

          进程 , 为线程提供一个资源共享的空间

          一个进程中默认是由一个主线程

        进程和线程的使用准则:

          计算密集型 : 多进程

          IO密集型 : 多线程

        线程创建的不是越多越好 , 线程之间切换时 , 要做上下文管理 .

    4. Python线程编写

      GIL锁 : 全局解释器锁 . 用于限制一个进程中同一时刻只有一个县城北CPU调度 . 默认GIL锁在执行100个CPU指令(过期时间)后 , 执行下一个线程 . 

      由于线程是CPU工作的最小单元 , 创建线程可以利用多核优势实现并行操作 . 

      注意 : 线程是为了工作 .

    线程的应用 :

    import threading
    
    def func(arg):
        print(arg)
    
    t = threading.Thread(target=func,args=(11,))
    t.start()
    
    print(123)
    
    """
    结果:
    11
    123
    """
    1.基本应用
    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)
    
    """
    结果:
    123
    3
    9
    """
    2.主程序默认等子线程执行完毕
    import threading
    import time
    
    def func(arg):
        time.sleep(arg)
        print(arg)
    
    t1 = threading.Thread(target=func,args=(3,))
    t1.setDaemon(True)
    t1.start()
    
    t2 = threading.Thread(target=func,args=(9,))
    t2.setDaemon(True)
    t2.start()
    
    print(123)
    
    """
    结果:
    123
    """
    3.主程序终止则所有子线程终止
    import threading
    import time
    
    def func(arg):
        time.sleep(0.01)
        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=(9,))
    t2.start()
    t2.join(2) # 让主线程在这里等着,等到子线程t2执行完毕,才可以继续往下走。
    
    print(123)
    4.控制主程序等待子线程(最多等待时间)
    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
    """
    5. 线程名称
    import threading
    def func(arg):
        print(arg)
    
    t1 = threading.Thread(target=func,args=(11,))
    t1.start()
    # start 是开始运行线程吗?不是
    # start 告诉cpu,我已经准备就绪,你可以调度我了。
    print(123)
    6. 线程本质
    # 1. 常见
    def func(arg):
        print(arg)
    
    t1 = threading.Thread(target=func,args=(11,))
    t1.start()
    
    # 2. 不常见
    class MyThread(threading.Thread):
    
        def run(self):
            print(11111,self._args,self._kwargs)
    
    t1 = MyThread(args=(11,))
    t1.start()
    
    t2 = MyThread(args=(22,))
    t2.start()
    
    print('end')
    7. 面向对象的多进程
    • start            线程准备就绪,等待CPU调度
    • setName      为线程设置名称
    • getName      获取线程名称
    • setDaemon   设置为后台线程或前台线程(默认)
                         如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                          如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
    • join              逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

    5. 锁

      Python内置的一个全局解释器锁,锁的作用就是保证同一时刻一个进程中只有一个线程可以被CPU调度.

      Python语言的创始人在开发这门语言时 , 目的是快速把语言开发出来 , 如果加上GIL锁(C语言加锁) , 切换时按照100条字节指令来进行线程间的切换.

      1. Lock

        一次放一个

        线程安全 , 多线程操作时 , 内部会让所有线程排队处理 . 如 : list/dict/Queue

        线程不安全 + 人 => 排队处理

    import threading
    import time
    
    v = []
    lock = threading.Lock()
    
    def func(arg):
        lock.acquire()
        v.append(arg)
        time.sleep(0.01)
        m = v[-1]
        print(arg,m)
        lock.release()
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    """
    结果:
    0 0
    1 1
    2 2
    3 3
    4 4
    5 5
    6 6
    7 7
    8 8
    9 9
    """
    示例

      2. RLock

        一次放一个

    import threading
    import time
    v = []
    lock = threading.RLock()
    
    def func(arg):
        lock.acquire()
        v.append(arg)
        time.sleep(0.01)
        m = v[-1]
        print(arg,m)
        lock.release()
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    """
    结果:
    0 0
    1 1
    2 2
    3 3
    4 4
    5 5
    6 6
    7 7
    8 8
    9 9
    """
    示例

      3. BoundedSemaphore

        一次放任意量

    import time
    import threading
    
    num = int(input(">>>"))
    lock = threading.BoundedSemaphore(num)
    
    def func(arg):
        lock.acquire()
        print(arg)
        time.sleep(1)
        lock.release()
    
    for i in range(20):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    示例

      4. Condition

        每次放任意量

    import time
    import threading
    
    lock = threading.Condition()
    
    def func(arg):
        print('线程进来了')
        lock.acquire()
        lock.wait() # 加锁
    
        print(arg)
        time.sleep(1)
    
        lock.release()
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    while True:
        inp = int(input('>>>'))
    
        lock.acquire()
        lock.notify(inp)
        lock.release()
    方式一
    import time
    import threading
    
    lock = threading.Condition()
    
    def xxxx():
        print('来执行函数了')
        input(">>>")
        # ct = threading.current_thread() # 获取当前线程
        # ct.getName()
        return True
    
    def func(arg):
        print('线程进来了')
        lock.wait_for(xxxx)
        print(arg)
        time.sleep(1)
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    方式二

      5. Event

        一次放所有

    import time
    import threading
    
    lock = threading.Event()
    
    
    def func(arg):
        print('线程来了')
        lock.wait() # 加锁:红灯
        print(arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    input(">>>>")
    lock.set() # 绿灯
    
    
    lock.clear() # 再次变红灯
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    
    input(">>>>")
    lock.set()
    示例

      总结 :

        线程安全 , 列表和字典线程安全

        加锁的原因 :

          -- 非线程安全

          -- 控制一段代码

    6. threading.local

      作用 : 内部自动为每个线程维护一个空间(字典)

    import time
    import threading
    
    v = threading.local()
    
    def func(arg):
        # 内部会为当前线程创建一个空间用于存储:phone=自己的值
        v.phone = arg
        time.sleep(2)
        print(v.phone,arg) # 去当前线程自己空间取值
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    示例
    import time
    import threading
    
    DATA_DICT = {}
    
    def func(arg):
        ident = threading.get_ident()
        DATA_DICT[ident] = arg
        time.sleep(1)
        print(DATA_DICT[ident],arg)
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    View Code
    """
    以后:Flask框架内部看到源码 上下文管理
    
    """
    
    import time
    import threading
    INFO = {}
    class Local(object):
    
        def __getattr__(self, item):
            ident = threading.get_ident()
            return INFO[ident][item]
    
        def __setattr__(self, key, value):
            ident = threading.get_ident()
            if ident in INFO:
                INFO[ident][key] = value
            else:
                INFO[ident] = {key:value}
    
    obj = Local()
    
    def func(arg):
        obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1)
        time.sleep(2)
        print(obj.phone,arg)
    
    
    for i in range(10):
        t =threading.Thread(target=func,args=(i,))
        t.start()
    示例升级

    7. 线程池

      为了限制线程个数 , 线程不是越多越好 , 也不是越少越好 , 控制线程数可以提高效率.

    from concurrent.futures import ThreadPoolExecutor
    import time
    
    def task(a1,a2):
        time.sleep(2)
        print(a1,a2)
    
    # 创建了一个线程池(最多5个线程)
    pool = ThreadPoolExecutor(5)
    
    for i in range(40):
        # 去线程池中申请一个线程,让线程执行task函数。
        pool.submit(task,i,8)
    View Code

    8. 生产者消费者模型

      三部件 : 

        生产者 : 

          队列 : 先进先出

          栈    : 后进先出

        消费者

      生产者消费者模型解决了不用一直等待的问题 . 

    import time
    import queue
    import threading
    
    q = queue.Queue() # 线程安全
    
    def producer(id):
        """
        生产者
        :return:
        """
        while True:
            time.sleep(2)
            q.put('包子')
            print('厨师%s 生产了一个包子' %id )
    
    for i in range(1,4):
        t = threading.Thread(target=producer,args=(i,))
        t.start()
    
    
    def consumer(id):
        """
        消费者
        :return:
        """
        while True:
            time.sleep(1)
            v1 = q.get()
            print('顾客 %s 吃了一个包子' % id)
    
    for i in range(1,3):
        t = threading.Thread(target=consumer,args=(i,))
        t.start()
    View Code

      Python进程                                                                           

      进程是CPU资源分配的最小单元.

      进程之间数据不共享.

    data_list = []
    def task(arg):
        data_list.append(arg)
        print(data_list)
    
    
    def run():
        for i in range(10):
            p = multiprocessing.Process(target=task,args=(i,))
            # p = threading.Thread(target=task,args=(i,))
            p.start()
    
    if __name__ == '__main__':
        run()
    进程
    class MyProcess(multiprocessing.Process):
    
        def run(self):
            print('当前进程', multiprocessing.current_process())
    
    def run():
        p1 = MyProcess()
        p1.start()
    
        p2 = MyProcess()
        p2.start()
    
    if __name__ == '__main__':
        run()
    类继承方式创建进程

    1. 进程之间资源共享

    linux:
        q = multiprocessing.Queue()
    
    
        def task(arg, q):
            q.put(arg)
    
    
        def run():
            for i in range(10):
                p = multiprocessing.Process(target=task, args=(i, q,))
                p.start()
    
            while True:
                v = q.get()
                print(v)
    
        run()
    
    
    windows:
    def task(arg, q):
        q.put(arg)
    
    
    if __name__ == '__main__':
        q = multiprocessing.Queue()
        for i in range(10):
            p = multiprocessing.Process(target=task, args=(i, q,))
            p.start()
        while True:
            v = q.get()
            print(v)
    Queue方法
    Linux:
        m = multiprocessing.Manager()
        dic = m.dict()
        
        
        def task(arg):
            dic[arg] = 100
        
        
        def run():
            for i in range(10):
                p = multiprocessing.Process(target=task, args=(i,))
                p.start()
        
            input('>>>')
            print(dic.values())
        
        
        if __name__ == '__main__':
            run()
    windows:
    
    
        def task(arg, dic):
            time.sleep(2)
            dic[arg] = 100
        
        
        if __name__ == '__main__':
            m = multiprocessing.Manager()
            dic = m.dict()
        
            process_list = []
            for i in range(10):
                p = multiprocessing.Process(target=task, args=(i, dic,))
                p.start()
        
                process_list.append(p)
        
            while True:
                count = 0
                for p in process_list:
                    if not p.is_alive():
                        count += 1
                if count == len(process_list):
                    break
            print(dic)
    Manage方法

    2. 进程锁

    import time
    import threading
    import multiprocessing
    
    lock = multiprocessing.RLock()
    
    def task(arg):
        print('鬼子来了')
        lock.acquire()
        time.sleep(2)
        print(arg)
        lock.release()
    
    if __name__ == '__main__':
        p1 = multiprocessing.Process(target=task,args=(1,))
        p1.start()
    
        p2 = multiprocessing.Process(target=task, args=(2,))
        p2.start()

      进程锁跟线程锁的编写方式类似 , 线程锁的所有方法 , 进程锁都有.

    3. 进程池

    import time
    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    
    def task(arg):
        time.sleep(2)
        print(arg)
    
    if __name__ == '__main__':
    
        pool = ProcessPoolExecutor(5)
        for i in range(10):
            pool.submit(task,i)
    View Code

    4. 初识爬虫

      安装 : pip3 install requests   和   pip3 install beautifulsoup4   模块

      requests 模块模拟浏览器发送请求

        --- 本质 requests.get(...):

            -- 创建socket客户端

            -- 连接[阻塞]

            -- 发送请求

            -- 接受请求[阻塞]

            -- 断开连接

    import requests
    from bs4 import BeautifulSoup
    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    
    
    # 模拟浏览器发送请求
    # 内部创建 sk = socket.socket()
    # 和抽屉进行socket连接 sk.connect(...)
    # sk.sendall('...')
    # sk.recv(...)
    
    def task(url):
        print(url)
        r1 = requests.get(
            url=url,
            headers={
                'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
            }
        )
    
        # 查看下载下来的文本信息
        soup = BeautifulSoup(r1.text,'html.parser')
        print(soup.text)
        # content_list = soup.find('div',attrs={'id':'content-list'})
        # for item in content_list.find_all('div',attrs={'class':'item'}):
        #     title = item.find('a').text.strip()
        #     target_url = item.find('a').get('href')
        #     print(title,target_url)
    
    def run():
        pool = ThreadPoolExecutor(5)
        for i in range(1,50):
            pool.submit(task,'https://dig.chouti.com/all/hot/recent/%s' %i)
    
    
    if __name__ == '__main__':
        run()
    爬虫示例
  • 相关阅读:
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 390 消除游戏
    Java实现 LeetCode 390 消除游戏
  • 原文地址:https://www.cnblogs.com/xiangweilai/p/9620734.html
Copyright © 2011-2022 走看看