• python高级编程——锁


     锁

              在使用用的过程中需要导入threading模块的Lock类

     使用锁:

      当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
      线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互 斥锁。 
      互斥锁为资源引入一个状态:锁定/非锁定。
     

    锁的语法

      创建锁、锁定锁、释放锁

    from threading import Lock
    
    # 创建锁
    mutex = Lock()
    # 获取锁(上锁)
    mutex.acquire()
    # 释放锁(解锁)
    mutex.release()

      在锁定锁的过程中acquire()方法可以接受一个blocking参数,

        如果设定blocking为True,则当前线程会堵塞,直到获取到这个锁为止(如果没有 指定,那么默认为True) 

        如果设定blocking为False,则当前线程不会堵塞

      上锁和解锁的过程(假设是多线程调度):

        这个锁一般是为共享资源服务的,即多个线程同时使用共享资源。这个锁同一时间只能有一个线程调度,其他线程阻塞,只有当前调度的线程释放这个锁,阻塞的线程才能调度。

      锁的优点:

        确保了某段关键代码只能有一个线程从头到尾完整的执行。

      锁的缺点:

        组织了多线程的并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大的降低了;代码中可能存在多个锁,如果多个线程拥有多个锁,容易造成死锁。

      死锁的现象(实例):

    # 死锁 两者都没有释放对方需要的锁,而释放的条件恰好是获取对方释放所需要的锁
    # 线程1
    class MyThread1(threading.Thread):
        def __init__(self):
            super().__init__()
    
        def run(self):
            # 线程1获取A锁
            if mutexA.acquire():
                print(self.name+"-----do1---up-----")
                sleep(1)
                # 此时线程2获取了B锁,需要等待线程2释放B锁
                if mutexB.acquire():
                    print(self.name + "-----do1---down-----")
                    mutexB.release()
                mutexA.release()
    
    # 线程2
    class MyThread2(threading.Thread):
        def __init__(self):
            super().__init__()
    
        def run(self):
            # 线程2获取B锁
            if mutexB.acquire():
                print(self.name + "-----do2---up-----")
                sleep(1)
                # 此时线程1获取了A锁,需要等待线程1释放A锁
                if mutexA.acquire():
                    print(self.name + "-----do2---down-----")
                    mutexA.release()
                mutexB.release()
    
    
    mutexA = threading.Lock()
    mutexB = threading.Lock()
    
    
    if __name__ == '__main__':
        # 线程1和线程2同时执行
        t1 = MyThread1()
        t2 = MyThread2()
        t1.start()
        t2.start()    

      避免死锁的方法:银行家算法

    多进程与多线程比较及选择

     是否采用多任务处理,取决于我们的任务类型

     如果是计算密集型,需要大量的CPU资源进行运算,代码的运行效率至关重 要,这样的任务一般不使用多线程进行,因为频繁的任务调度会拖慢CPU的
    运算。

     如果是IO密集型,涉及到硬盘读写,网络读写等的任务,更多的时间在等待 IO操作完成,这一类任务可以放到多线程或多进程中来进行。

    单线程、多线程、多进程(一起实现同一代码的时间)

    # 单线程、多线程、多进程的使用及不同
    # 简单的求和
    def fib(x):
        res = 0
        for i in range(100000000):
            res += i*x
        return res
    
    
    # 阶乘
    def fac(x):
        if x < 2:
            return 1
        return x*fac(x-1)
    
    
    # 简单的求和
    def sum(x):
        res = 0
        for i in range(50000000):
            res += i*x
        return res
    
    
    # 函数列表
    funcs = [fib, fac, sum]
    n = 100
    
    
    class MyThread(threading.Thread):
        def __init__(self, func, args, name=""):
            super().__init__()
            self.name = name
            self.func = func
            self.args = args
            self.res = 0
    
        def getResult(self):
            return self.res
    
        def run(self):
            print("starting ", self.name, " at: ", ctime())
            self.res = self.func(self.args)
            print(self.name, "finished at: ", ctime())
    
    
    def main():
        nfuncs = range(len(funcs))
    
        print("单线程".center(30, "*"))
        start = time()
        for i in nfuncs:
            print("start {} at: {}".format(funcs[i].__name__, ctime()))
            start_task = time()
            print(funcs[i](n))
            end_task = time()
            print("任务 耗时:", end_task-start_task)
            print("{} finished at: {}".format(funcs[i].__name__, ctime()))
    
        end = time()
        print("单线程运行时间:", end-start)
        print("单线程结束:".center(30, "*"))
    
        print()
        print("多线程".center(30, "*"))
        start = time()
        threads = []
        for i in nfuncs:
            # 一个线程绑定一个函数
            t = MyThread(funcs[i], n, funcs[i].__name__)
            threads.append(t)
    
        for i in nfuncs:
            # 同时启动线程
            threads[i].start()
    
        for i in nfuncs:
            threads[i].join()
            print(threads[i].getResult())
        end = time()
        print("多线程运行时间:", end-start)
        print("多线程结束:".center(30, "*"))
    
        print()
        print("多进程".center(30, "*"))
        start = time()
        process_list = []
        for i in nfuncs:
            # 一个进程绑定一个函数
            t = Process(target=funcs[i], args=(n, ))
            process_list.append(t)
    
        for i in nfuncs:
            # 同时启动进程
            process_list[i].start()
    
        for i in nfuncs:
            process_list[i].join()
        end = time()
        print("多进程运行时间:", end - start)
        print("多进程结束:".center(30, "*"))
    
    
    if __name__ == "__main__":
        main()
  • 相关阅读:
    对double数据类型的数据保留两位小数,并且进行四舍五入
    div位置设置
    每天一算法 -- (排序算法总结)
    SQL行转列
    设计模式的六大原则
    每天一算法 -- (插入排序)
    每天一算法 -- (选择排序)
    通用扩展函数--类型转换
    wcf和webservice
    Cookie的介绍及使用
  • 原文地址:https://www.cnblogs.com/aitiknowledge/p/11442905.html
Copyright © 2020-2023  润新知