• python全栈学习--day41(线程概念,线程的特点,进程和线程的关系,线程和python 理论知识,线程的创建)


     队列

      队列:先进先出,数据进程安全

      管道 + 锁

      生产者消费者模型:解决数据供需不平衡

    多个进程取值,不会发生数据不一致。数据进程安全

    队列实现方式是 管道 + 锁

    管道

      双向通信  数据进程不安全

      EOFError:

        管道是由操作系统进行引用计数的。

        必须在所有进程中关闭管道后才能生成EOFError 异常

    管道和数据共享,数据是不安全的。

    数据共享(不常用)

      Manager

      list dict 数据进程不安全的

    队列是内置锁,所以别的应用调用它,是安全的。

    凡是涉及到手动加锁的,都是不安全的。常用的一般都是消息中间件

    进程池:

      存放进程的容器

      在进程创建之初,创建固定个数的进程在执行

      会被多个任务循环利用

      节省了进程创建和销毁的时间开销

      降低了操作系统调度进程的压力

    信号量和进程池的区别

      信号量n个任务开启n个进程。

        但同一时间只能有固定个数的进程在执行

      进程池 n 个任务开启固定个数的进程

        因此同一时间只能有固定个数的进程在执行

    例如:200个任务--200个进程 4个进程执行 信号量

        200个任务--4个进程  4个进程执行 进程池

    一个进程是等待,一个是任务等待。

    信号量 n 个任务开启n个进程。

      但同一时间只能有固定个数的进程在执行

      进程在等待被执行

    进程池 n 任务开启固定个数的进程

      因此同一时间只能有固定个数的进程在执行

      任务在等待被执行

    import time
    from multiprocessing import Pool
    def wahaha(i):
        time.sleep(1)
        print('*'*i)
    if  __name__ == "__main__":
        p  =  Pool(5)
        p.map(func=wahaha,iterable=range(10))
    实例源码

    说明:

    自带close和join

    但是参数必须是一个iterable

    不能获取返回值

    import time
    from multiprocessing import Pool
    def wahaha(i):
        time.sleep(1)
        print('*'*i)
    if  __name__ == "__main__":
        p  =  Pool(5)
        p.map(func=wahaha,iterable=range(10))
    
        res_l = []
        for i in range(10):
            res = p.apply_async(func=wahaha,args=[i,])
            res_l.append(res)
        for i in res_l:print(i.get())
        p.close()     # 不能再提交新的任务
        p.join()      #等待池中的任务都执行完
    

     

    *
    **
    ***
    ****
    ******
    *****
    *******
    ********
    *********

    *
    ***
    **
    None
    None
    None
    None
    ****
    None
    ******
    *****
    None
    None
    ********
    *********
    *******
    None
    None
    None

    主进程默认等待子进程结束----守护进程

    普通的进程:根据你调用的函数执行结束它就结束了

    进程池里的进程

       没有返回值

          在提交任务之后:

          p.close()  #不能在提交新的任务

          p.join()  #等待池中的任务都执行完

        有返回值的时候:

          在提交任务之后:

          

    for i in res_l:print(i.get())
    

    回调函数

      回调函数在什么时候执行

        子进程的任务执行完毕以后立即触发

      回调函数的参数

        子进程的返回值

      回调函数是由谁执行的

        主进程执行的

      在哪儿用?

        爬虫:

          如果要爬取多个格式相同的网页

          真正影响程序效率的是网络的延迟

          计算 分析 处理网页的时间是很快的

    #500

      有回调函数

      没有回调函数快

    进程:操作系统管理进程,进程是执行任务,资源的隔离。在一个操作系统中,同一时间,有多个任务。多个任务之间的内存必须隔离开。使用QQ的时候,还能使用微信

    并发

    并发的要求日益增加,聊天----开子进程。你可以看电影-----开子进程,缓存其他电影。开启一个子进程的开销,是很大的。操作系统在进程之间的切换 ,时间开销也很大。

    进程之间的通信

    数据共享:时间开销

    如果多个子进程之间的数据共享量过多的时候,就不应该将这些数据隔离开。一个进程-----实现不了并发。

    你既不希望数据隔离,还要实现并发的效果。

    线程

    线程是轻量级的进程,线程的创建和销毁所需要的时间开销都非常小,线程直接使用进程的内存,线程不能独立存在,要依赖于进程。

    进程---资源分配的最小单位

    线程---CPU调度的最小单位

      轻型进程:创建、销毁、切换、开销比进程小

      数据不隔离

      可以并发

      依赖进程

    每一个进程里至少有一个线程,进程负责资源、线程负责执行代码。

    python程序运行起来------进程

    进程-----管理整个程序的内存。

      存储全局的变量:内置的函数  全局的名字

    线程-----执行代码

    利用python开启多线程---------并发

    import os
    import time
    from threading import Thread
    from multiprocessing import Process
    def func(i):
        print('---->',os.getppid())
        time.sleep(1)
        print('*',i)
    
    if __name__=='__main__':
        print(os.getppid())
        start = time.time()
        thread_lst = []
        for i in range(20):
            t = Thread(target=func,args=(i,))
            t.start()
            print('---->',t.name,t.ident)
            thread_lst.append(t)
        for t in thread_lst:t.join()
        print(time.time()-start)
    
        start = time.time()
        process_lst = []
        for i in range(20):
            p = Process(target=func,args=(i,))
            p.start()
            process_lst.append(p)
        for p in process_lst:p.join()
        print(time.time()-start)
    

      执行输出:

    3624
    ----> 3624
    ----> Thread-1 2168
    ----> Thread-2 1600
    ----> 3624
    ----> 3624
    ----> Thread-3 13856
    ----> 3624
    ----> Thread-4 6100
    ----> 3624
    ----> Thread-5 3712
    ----> 3624
    ----> Thread-6 14408
    ----> 3624
    ----> Thread-7 4480
    ----> 3624
    ----> Thread-8 3760
    ----> 3624
    ----> Thread-9 16268
    ----> Thread-10 11848
    ----> 3624
    ----> Thread-11 4244
    ----> 3624
    ----> Thread-12 13804
    ----> 3624
    ----> Thread-13 5788
    ----> 3624
    ----> Thread-14 1028
    ----> 3624
    ----> Thread-15 6608
    ----> 3624
    ----> Thread-16 15312
    ----> 3624
    ----> Thread-17 14580
    ----> 3624
    ----> Thread-18 6564
    ----> 3624
    ----> Thread-19 11672
    ----> 3624
    ----> Thread-20 11396
    ----> 3624
    * 0
    * 1
    * 2
    * 3
    * 4
    * 5
    * 6
    * 7
    * 8
    * 9
    * 10
    * 11
    * 12
    * 13
    * 14
    * 15
    * 16
    * 17
    * 18
    * 19
    1.107273817062378
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    ----> 4468
    * 0
    * 1
    * 3
    * 2
    * 4
    * 5
    * 6
    * 7
    * 9
    * 8
    * 10
    * 11
    * 15
    * 12
    * 13
    * 16
    * 14
    * 18
    * 17
    * 19
    1.9786567687988281

    效率问题:线程快 进程慢

    同一个进程下的多个线程进程号相同:线程号不同

    if __name__ == '__main__' : 开启进程 必须有这句话 但是开启线程不需要
    这种现象只在windows操作系统上才出现


    数据的共享问题:在进程之间数据隔离,在线程之间数据共享

    def manager():
        global n
    from threading import Thread
    n = 100
    t = Thread(target=manager)
    t.start()
    t.join()
    print('-------->',n)
    

    GIL —— 全局解释器锁

    锁线程 :在计算的时候 同一时刻只能有一个线程访问CPU

    线程锁限制了你对CPU的使用,但是不影响web类或者爬虫类代码的效率

    我们可以通过启动多进程的形式来弥补这个问题

    import time
    from threading import Thread
    def func1():
        while True:
            time.sleep(1)
            print('子线程')
    
    def func2():
        time.sleep(5)
        print('子线程2')
    
    t = Thread(target=func1)
    t2 = Thread(target=func2)
    t.setDaemon(True)
    t.start()
    t2.start()
    print('主线程')
    守护线程

    # 主进程的守护进程是在主进程的代码结束,守护进程就结束了
    # 主线程的守护线程会在非守护线程的所有线程执行完毕之后才结束

  • 相关阅读:
    SQL Server2005重新安装不上的问题及其解决(转)
    取消2003默认共享
    自写生成实体类工具
    双核886针CPU简明制作教程
    VS 2008 在安装SP1后智能提示变成英文的解决办法
    VS2008 安装盘的问题
    拖放 DataGrid 列摘自MSDN
    VB.net SP1 的兼容性问题
    Windows Server 2008+VS2008
    Combobox 的解决方法
  • 原文地址:https://www.cnblogs.com/haowen980/p/9041931.html
Copyright © 2020-2023  润新知