欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python高级编程——锁

程序员文章站 2022-04-11 08:25:13
锁 在使用用的过程中需要导入threading模块的Lock类 使用锁: 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互 斥锁。 互斥锁为资源引入一个状态:锁定/非锁定。 锁的语法 创建锁、锁定锁、释放锁 在锁定锁的过 ......

 锁

          在使用用的过程中需要导入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()    

  避免死锁的方法:(银行家算法,看实例)

# 银行家算法
class task1(threading.thread):
    def __init__(self):
        super().__init__()

    def run(self):
        while true:
            if lock1.acquire():
                print("task1".center(20, "-"))
                sleep(0.5)
                lock2.release()


class task2(threading.thread):
    def __init__(self):
        super().__init__()

    def run(self):
        while true:
            if lock2.acquire():
                print("task2".center(20, "-"))
                sleep(0.5)
                lock3.release()


class task3(threading.thread):
    def __init__(self):
        super().__init__()

    def run(self):
        while true:
            if lock3.acquire():
                print("task3".center(20, "-"))
                sleep(0.5)
                lock1.release()


lock1 = threading.lock()
lock2 = threading.lock()
lock3 = threading.lock()
lock2.acquire()
lock3.acquire()

t1 = task1()
t2 = task2()
t3 = task3()
t1.start()
t2.start()
t3.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()