zoukankan      html  css  js  c++  java
  • 并发编程|线程

    线程

      进程是资源的单位,而线程是执行单位。开启进程需要内存空间,这就好比造一个生产车间,好比进程内地代码就是生产资料,有变量,有函数,有类等等。而进程就是生产线,把这些生产资料放在线程这条生产线,才能生产出结果。每个进程都自带线程,线程才是真正的执行单位,进程为线程提供资源。

      线程与进程(进程:https://www.cnblogs.com/huaiXin/p/11329260.html)。进行比较,开启进程需要申请内存空间,还需要‘拷贝’主进程的代码。但是开启线程不需要申请内存空间。一个进程内可以有多个线程,并且线程与线程之间是数据共享的。

    开启现成的两种方式

      开启线程需要引入threading模块中的Thread这个类。开启方式一种是引用Thread类开启,另一种继承Thread类,自定义一个类开启。

    '''
    开启线程的第一种方式
    '''
    from threading import Thread  # 调用线程模块
    import time
    
    def task(name):
        print(f'{name}来了')
        time.sleep(3)
        print(f"{name}结束了")
    
    t = Thread(target=task, args=('旷哥',))   # 创建线程对象
    t.start()       # 启动线程
    print('')
    '''
    开启线程的第二种方式
    '''
    from threading import Thread
    import time
    class MyThread(Thread):   # 继承Thread这个类
        def __init__(self, name):
            super().__init__()
            self.name = name
        def run(self):           #  写run方法
            print(f'{self.name}来了')
            time.sleep(2)
            print(f'{self.name}结束')
    
    t = MyThread('旷哥')
    t.start()
    print('')

    线程对象及其他方法

    '''
    current_thread : 查看线程对象方法
    os.getpid: 查看PID端口号
    active_count: 查看当前活跃的线程数
    t.daemon: 设置伴随进程
    '''
    
    from threading import Thread, current_thread ,active_count # 调用线程模块
    import time
    import os
    
    def task(name):
        print(f'{name}来了')
        print('',os.getpid())   # 查看PID端口号
        print('current_thread:', current_thread().name)
        time.sleep(3)
        print(f"{name}结束了")
    
    t = Thread(target=task, args=('旷哥',))   # 创建线程对象
    t.daemon = True
    t.start()       # 启动线程
    print('',os.getpid())
    print(active_count())   # 查看当前活跃的线程数
    print('',current_thread().name)

    线程互斥锁  

      当多个线程同时操作统一数据,数据是不安全的,需要加锁处理,讲线程并行操作数据改为串行操作数据。 

    '''
    线程互斥锁
        当多个线程同时操作统一数据,数据是不安全的
        需要加锁,讲线程并行操作数据改为串行操作数据
    '''
    from threading import Thread, Lock
    import time
    
    n = 100
    def func(L):
        global n
        L.acquire()  # 抢锁
        temp = n
        time.sleep(0.1)  # 模拟网络延迟
        temp -= 1
        n = temp
        L.release()  # 放锁
    
    t_list = []
    numtext = Lock()
    for i in range(100):    # 开启100个线程
        t = Thread(target=func, args=(numtext,))
        t.start()
        t_list.append(t)
    for k in t_list:
        k.join()  # 等待所有线程结束
    print(n)  # 打印共享的N

     GIL全局解释器锁

      GLI(global interproter Lock)是cpython全局解释器锁。它的本质是一把互斥锁,将并发变成串行牺牲效率保证安全性。cpython中每一个进程都有自身的线程,python中的垃圾回收机制,也是一行代码和模块,启动python是也需要启动垃圾回收机制代码,这也需要一个线程。它们都需要python解释器经行编译运行,而每个进程只有一个python解释器,进程下的所有线程都共用这个解释器,为了保证线程安全运行,就需要GIL对线程进行保护。GIL的特点:单进程下无法利用多核优势。而且多不同的数据加载不同的锁处理。

      python开多线程多进程,视情况而定。当计算密集型时多任务,单核条件下应使用开多线程:多核条件下计算量在较小时开启多线程,如果不是就开启多进程。当I/O密集型多任务是无论单核多核,开启多线程。

    '''
    计算密集型
        总结: 计算密集型在单核条件下。应开线程, 多核条件下, 在计算量百万次一下开线程,以上开进程
    '''
    import time
    from multiprocessing import Process
    from threading import Thread
    import os
    
    def sun():
        i = 0
        while i < 1e5:
            i += 1
    
    if __name__ == '__main__':
        p_list = []
        print(os.cpu_count())
        start = time.time()
        for i in range(4):
            # p = Process(target=sun,)  # 0.9663281440734863
            p = Thread(target=sun,)     # 0.37197113037109375
            p.start()
            p_list.append(p)
        for p in p_list:
            p.join()
        print(f'用时{time.time()-start}')
    '''
    I/O密集型
        总结:
            单核与多核条件开启线程
    '''
    import time
    from multiprocessing import Process
    from threading import Thread
    import os
    
    def sun():
        i = 0
        while i < 1e3:
            time.sleep(0.1)
            i += 1
    
    if __name__ == '__main__':
        p_list = []
        print(os.cpu_count())
        start = time.time()
        for i in range(4):
            # p = Process(target=sun,)  # 11.024189472198486
            p = Thread(target=sun,)     # 10.05493450164795
            p.start()
            p_list.append(p)
        for p in p_list:
            p.join()
        print(f'用时{time.time()-start}')
    线程与进程优势

    死锁现象与递归锁

      当使用锁过多时,可能会出现死锁现象。

    '''
    死锁现象
    '''
    import time
    from threading import Thread, Lock
    
    muxB = Lock()
    muxA = Lock()
    class MyThread(Thread):
        def run(self):
            self.func1()
            self.func2()
            pass
        def func1(self):
            muxA.acquire()
            print(f'{self.name}抢到A锁')
            muxB.acquire()
            print(f'{self.name}抢到B锁')
            muxB.release()
            print(f'{self.name}释放B锁')
            muxA.release()
            print(f'{self.name}释放A锁')
    
        def func2(self):
            muxB.acquire()
            print(f'{self.name}抢到B锁')
            time.sleep(0.1)
            muxA.acquire()
            print(f'{self.name}抢到A锁')
            muxA.release()
            print(f'{self.name}释放A锁')
            muxB.release()
            print(f'{self.name}释放B锁')
    for i in range(10):
        t = MyThread()
        t.start()
    # 结果
    Thread-1抢到A锁
    Thread-1抢到B锁
    Thread-1释放B锁
    Thread-1释放A锁
    Thread-2抢到A锁
    Thread-1抢到B锁   # 卡在此处
    死锁现象

      递归锁

      递归锁是threading模块下RLock。这中锁多个对象每抢一次锁,内部加1计数,每释放一次就减一。计数标志为0时,其他对象才可以抢锁。且共用一把锁。

    '''
    递归锁
    '''
    
    import time
    from threading import Thread, RLock
    
    muxB = muxA = RLock()
    
    class MyThread(Thread):
        def run(self):
            self.func1()
            self.func2()
            pass
        def func1(self):
            muxA.acquire()
            print(f'{self.name}抢到A锁')
            muxB.acquire()
            print(f'{self.name}抢到B锁')
            muxB.release()
            print(f'{self.name}释放B锁')
            muxA.release()
            print(f'{self.name}释放A锁')
    
        def func2(self):
            muxB.acquire()
            print(f'{self.name}抢到B锁')
            time.sleep(0.1)
            muxA.acquire()
            print(f'{self.name}抢到A锁')
            muxA.release()
            print(f'{self.name}释放A锁')
            muxB.release()
            print(f'{self.name}释放B锁')
    for i in range(10):
        t = MyThread()
        t.start()
    递归锁

      信号量

      也是一种锁的应用。在threading模块下Semaphore方法。控制锁的个数。

    import time
    from threading import Thread, Semaphore
    
    s = Semaphore(2)  # 控制锁的各所,同时有两个锁
    n = 10
    def func1(i):
        global n
        s.acquire()
        temp = n
        time.sleep(1)
        temp -= 1
        n = temp
        print(f'{i}操作后{n}')
        s.release()
    
    for i in range(10):
        t = Thread(target=func1, args=(i,))
        t.start()
    信号量

    event事件

      在threading模块下的Event方法,使子进程之间可会互相等待。

    import time
    from  threading import Thread, Event
    
    e = Event()
    
    def func1():
        print('红灯亮起!')
        time.sleep(3)
        print('绿灯亮起!')
        e.set()
    
    def func2(name):
        print(f'{name}准备!')
        e.wait()
        print(f'{name}出发!')
    
    # 线程t1等待线程t
    t = Thread(target=func1, )
    t.start()
    for i in range(10):
        t1 = Thread(target=func2, args=(f'车手{i}号',))
        t1.start()

      

  • 相关阅读:
    Flask正则路由,异常捕获和请求钩子
    Flask的路由,视图和相关配置
    Flask搭建虚拟环境
    Flask框架简介
    Django的类视图和中间件
    Django中的cookies和session
    Django请求与响应
    第6章 服务模式 Service Interface(服务接口)
    第6章 服务模式
    第5章分布式系统模式 Singleton
  • 原文地址:https://www.cnblogs.com/huaiXin/p/11340688.html
Copyright © 2011-2022 走看看