zoukankan      html  css  js  c++  java
  • 线程入门

    一、线程

    初识别线程

    在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
    在工厂中, 每个车间都有房子,而且每个车间默认就有一条流水线.

    操作系统 ---> 工厂
    进程 ---> 车间
    线程 ---> 流水线
    cpu ---> 电源

    线程:cpu最小的执行单位
    进程:资源集合/资源单位.
    线程运行 = 运行代码
    进程运行 = 各种资源 + 线程

    右键运行程序:申请内存空间,先把解释器丢进去并且把代码丢进去(进程做的),运行代码(线程)

    进程和线程的区别

    过程描述的区别:

    • 线程 --> 单指代码的执行过程

    • 进程--> 资源的申请与销毁的过程

    内存空间的却别:

    • 进程内存空间彼此隔离

    • 同一个进程下的超线程共享资源

    进程和线程的创建速度:

    • 进程需要是年轻资源开辟空间:慢
    • 线程只是告诉操作系统一个执行方案:快

    二、线程开启的两种方式

    方式一:

    from threading import Thread
    
    def task():
        print('子线程...')
        
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()
        print('主')
    

    方式二:

    from threading import Thread
    
    class Task(Thread):
        def run(self):
            pass
        
    if __name__ == '__main__':
    	t = Task()
        t.start()
        print('主')
    

    三、子线程和子进程的创建速度

    进程和线程的创建速度

    开启子进程需要申请资源开辟空间: 慢

    开启子线程只是告诉操作系统一个执行方案: 快

    开启子线程的打印效果:

    # 子线程 is running
    # 主
    # 子线程 is end
    

    开启子进程打印效果:

    # 主
    # 子进程 is running
    # 子进程 is end
    

    代码:

    from threading import Thread
    from multiprocessing import Process
    import time
    
    def task(name):
        print(f'{name} is running')
        time.sleep(2)
        print(f'{name} is end')
        
    if __name__ == '__main__':
        t = Thread(target=task, args=('子线程',))
        p = Process(target=task, args=('子进程',))
        # t.start()
        p.start()
        print('主')
    

    四、子线程共享资源

    from threading import Thread
    import time, os
    
    x = 100
    def task():
        global x
        x = 50
        print(os.getpid())  # 5204
        
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()
        time.sleep(2)
        print(x)  # 50
        print(os.getpid()) # 5204
    

    五、线程的join方法

    from threading import Thread
    import time
    
    def task(name, n):
        print(f'{name} start')
        time.sleep(n)
        print(f'{name} end')
        
    if __name__ == '__main__':
        t1 = Thread(target=task, args=('线程1', 1))
        t2 = Thread(target=task, args=('线程2', 2))
        t3 = Thread(target=task, args=('线程3', 3))
        start = time.time()
        t1.start()
        t2.start()
        t3.start()
        t1.join() # 1s
        t2.join() # 2s
        t3.join() # 3s
        end = time.time() # 3.0039877891540527
        print(end - start)
    

    六、了解进程的join

    from multiprocessing import Process
    from threading import Thread
    import time
    
    def task():
    	print('进程 开启')
        time.sleep(10)
        print('进程 结束')
        
    def taks2():
        print('子线程 开启')
        time.sleep(2)
        print('子线程 结束')
        
    if __name__ == '__main__':
        p = Process(target=task)
        t = Thread(target=task2)
        t.start() # 开线程
        p.start() # 开进程
        print('子进程join开始')
        p.join() # 主进程的主线程等待子进程运行结束
        print('主')
    

    七、线程相关的其他方法(了解)

    # Thread实例对象的方法
    isAlive():  # 返回线程是否活动的。
    getName():  # 返回线程名。
    setName():  # 设置线程名
        
    threading模块提供的一些方法:
    threading.currentThread():  # 返回当前的线程变量
    threading.enumerate():  # 返回一个包含正在运行的线程的list,正在运行指线程启动后、结束							前,不包括启动前和终止后的线程。
    threading.activeCount():  # 返回正在运行的线程数量,与len(threading.enumerate())								有相同的效果
    

    八、守护线程(了解)

    守护线程首先是一个线程

    • 守护线程守护到当前进程运行结束。
    • ps:比如有未完成的子进程阶段会守护,比如有未完成的其他子线程也均会守护。

    守护进程首先是一个进程

    • 守护进程守护到当前进程的最后一行代码结束。
    # 守护线程守护到当前进程结束
    from threading import Thread
    import threading
    import time
    
    def threadtask(name):
        print(f'{name} start')
        print(time.sleep(20))
        print(f'{name} end')
        
    def threadtask2(name):
        print(f'{name} start')
        time.sleep(10)
        print(threading.enumerate()) # [<_MainThread(MainThread, stopped 14544)>, <Thread(Thread-1, started daemon 13676)>, <Thread(Thread-2, started 13148)>]
        print(f'{name} end')
        
    if __name__ == '__main__':
        t = Thread(target=threadtask, args=('守护线程',))
        t2 = Thread(target=threadtask2, args=('子线程',))
        t.daemon = True
        t.start()
        t2.start()
        print('主')
        '''
        守护线程  start
        子线程 start
        主
        [<_MainThread(MainThread, stopped 15448)>, <Thread(Thread-1, started daemon 17520)>, <Thread(Thread-2, started 10356)>]
        子线程 end
    
        '''
        #  可以看到当主线程已经结束的时候,其他子线程没有结束的时候打印当前的活跃的线程发现有		守护线程。
    

    九、GIL全局解释器锁

    ​ Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然Python解释器中可以"运行"多个线程,但在任意时刻只有一个线程在解释器中运行。

    ​ 对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。在多线程环境中,Python虚拟机按以下方式执行:

    1. 设置GIL;
    2. 切换到一个线程去运行;
    3. 运行指定数量的字节码指令或者线程主动让出控制(可以调用 time.sleep(0));
    4. 把线程设置为睡眠状态;
    5. 解锁GIL;
    6. 再次重复以上所有步骤。

    在调用外部代码(如C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。

  • 相关阅读:
    Junit单元测试学习笔记(一)
    perl 函数参数传递与返回值(一)
    Oracle blob字段类型 文件读写实例
    测试沙龙的一些感悟
    常用排序算法选择排序
    perl 哈希(hash)学习笔记(一)
    perl 自定义包/模块的使用(正则表达式匹配email地址和ip)
    常用排序算法冒泡排序
    如何使用excel计算工龄
    畅想(3)打通编程的任督二脉 人工智能
  • 原文地址:https://www.cnblogs.com/17vv/p/11535044.html
Copyright © 2011-2022 走看看