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

    关于线程的一些事儿

                    理论知识

    全局解释器锁GIL

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

    对python虚拟机的访问有全局解释器锁(GIL)来控制,正式这个锁能保证同一时刻只有一个线程在运行。

    python线程模块的选择

    python提供了几个用于多线程编程的模块,包括thread,threading和Queue等。thread和threading模块允许程序员创建和管理线程,thread模块提供了基本的线程和锁的支持,threading提供了更高级别,功能更强的线程管理的功能,Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构。

                  threading模块

    multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性。

    线程的创建Threading.Thread类

    from threading import Thread
    import time
    def sayhi(name):
        time.sleep(2)
        print('%s say hello' %name)
    
    if __name__ == '__main__':
        t=Thread(target=sayhi,args=('egon',))
        t.start()
        print('主线程')
    from threading import Thread
    import time
    class Sayhi(Thread):
        def __init__(self,name):
            super().__init__()
            self.name=name
        def run(self):
            time.sleep(2)
            print('%s say hello' % self.name)
    
    
    if __name__ == '__main__':
        t = Sayhi('egon')
        t.start()
        print('主线程')

    互斥锁

    线程之间的数据安全问题:

    +=-= 赋值操作不安全(实际是含有三步骤:在取值后返回值时会有另外线程取值这样取的值还是未改变的)

    另外互斥锁可以开多个锁只要不一致的锁名 例:

    noodle_lock = Lock()
    fork_lock = Lock()

    from threading import Thread
    import os,time
    def work():
        global n
        temp=n
        time.sleep(0.1)
        n=temp-1
    
    if __name__ == '__main__':
        n=100
        l=[]
        for i in range(100):
            p=Thread(target=work)
            l.append(p)
            p.start()
        for p in l:
            p.join()

    递归锁

    死锁现象

    两把锁

    异步的

    操作的时候 抢到 一把锁之后还要再去抢第二把锁

    一个线程抢到一把锁

    另外一个线程抢到另一把锁

    递归锁能快速解决死锁问题

    # import time
    # from threading import Thread,Lock
    #
    # noodle_lock = Lock()
    # fork_lock = Lock()
    # def eat1(name):
    #     noodle_lock.acquire()
    #     print('%s拿到面条了'%name)
    #     fork_lock.acquire()
    #     print('%s拿到叉子了'%name)
    #     print('%s吃面'%name)
    #     time.sleep(0.3)
    #     fork_lock.release()
    #     print('%s放下叉子'%name)
    #     noodle_lock.release()
    #     print('%s放下面'%name)
    #
    # def eat2(name):
    #     fork_lock.acquire()
    #     print('%s拿到叉子了' % name)
    #     noodle_lock.acquire()
    #     print('%s拿到面条了'%name)
    #     print('%s吃面'%name)
    #     time.sleep(0.3)
    #     noodle_lock.release()
    #     print('%s放下面'%name)
    #     fork_lock.release()
    #     print('%s放下叉子' % name)
    #
    # if __name__ == '__main__':
    #     name_list = ['alex','wusir']
    #     name_list2 = ['nezha','yuan']
    #     for name in name_list:
    #         Thread(target=eat1,args=(name,)).start()
    #     for name in name_list2:
    #         Thread(target=eat2,args=(name,)).start()
    # import time
    # from threading import Thread,RLock
    #
    # fork_lock = noodle_lock = RLock()
    # def eat1(name):
    #     noodle_lock.acquire()
    #     print('%s拿到面条了'%name)
    #     fork_lock.acquire()
    #     print('%s拿到叉子了'%name)
    #     print('%s吃面'%name)
    #     time.sleep(0.3)
    #     fork_lock.release()
    #     print('%s放下叉子'%name)
    #     noodle_lock.release()
    #     print('%s放下面'%name)
    #
    # def eat2(name):
    #     fork_lock.acquire()
    #     print('%s拿到叉子了' % name)
    #     noodle_lock.acquire()
    #     print('%s拿到面条了'%name)
    #     print('%s吃面'%name)
    #     time.sleep(0.3)
    #     noodle_lock.release()
    #     print('%s放下面'%name)
    #     fork_lock.release()
    #     print('%s放下叉子' % name)
    #
    # if __name__ == '__main__':
    #     name_list = ['alex','wusir']
    #     name_list2 = ['nezha','yuan']
    #     for name in name_list:
    #         Thread(target=eat1,args=(name,)).start()
    #     for name in name_list2:
    #         Thread(target=eat2,args=(name,)).start()

    递归锁好不好?

      递归锁并不是一个好的解决方案

      死锁现象的发生不是互斥锁的问题

      而是程序员的逻辑有问题导致的

      递归锁能够快速的解决死锁问题

    递归锁

    迅速恢复服务  递归锁替换互斥锁

    在接下来的时间中慢慢把递归锁换成互斥锁

    信号量

    同进程的一样

    Semaphore管理一个内置的计数器,每当调用acquire()时内置的计数器-1,调用release()时内置计数器+1,计数器不能小于0,当计数器为0,acquire()将阻塞线程直到其他线程调用release()

    import time
    from threading import Semaphore,Thread
    
    def func(index,sem):
        sem.acquire()
        print(index)
        time.sleep(1)
        sem.release()
    
    if __name__ == '__main__':
        sem = Semaphore(5)
        for i in range(10):
            Thread(target=func,args=(i,sem)).start()

    事件

    和进程差不多

    import time
    import random
    from threading import Event,Thread
    def check():
        print('开始检测数据库连接')
        time.sleep(random.randint(1,5))  # 检测数据库连接
        e.set()  # 成功了
    
    def connect():
        for i in range(3):
            e.wait(0.5)
            if e.is_set():
                print('数据库连接成功')
                break
            else:
                print('尝试连接数据库%s次失败'%(i+1))
        else:
            raise TimeoutError
    
    e = Event()
    Thread(target=connect).start()
    Thread(target=check).start()

    条件Condition

    notify和wait都需要加上锁

    from threading import Condition,Thread
    def func(con,index):
        print('%s在等待'%index)
        con.acquire()
        con.wait()
        print('%s do something'%index)
        con.release()
    
    con = Condition()
    for i in range(10):
        t = Thread(target=func,args=(con,i))
        t.start()
    con.acquire()
    con.notify_all()
    con.release()
    # count = 10
    # while count > 0:
    #     num= int(input('>>>'))
    #     con.acquire()
    #     con.notify(num)
    #     count -= num
    #     con.release()

    定时器

    from threading import Timer
    def func():
        print('执行我啦')
    
    t = Timer(3600,func)
    t.start()
    print('主线程')

    队列

    LifoQueue

    PriorityQueue

    # from queue import LifoQueue
    # 栈 完成算法
    # lq = LifoQueue()
    # lq.put(1)
    # lq.put(2)
    # lq.put(3)
    # lq.put('a')
    # lq.put('b')
    # print(lq.get())
    # print(lq.get())
    # print(lq.get())
    # from queue import PriorityQueue
    # pq = PriorityQueue()
    # pq.put((15,'abc'))
    # pq.put((5,'ghi'))
    # pq.put((12,'def'))
    # pq.put((12,'aaa'))
    #
    # print(pq.get())
    # print(pq.get())
    # print(pq.get())
    
    # from queue import PriorityQueue
    # pq = PriorityQueue()
    # pq.put(15)
    # pq.put(5)
    # pq.put(12)
    # pq.put(12)
    #
    # print(pq.get())
    # print(pq.get())
    # print(pq.get())
    
    # from queue import PriorityQueue
    # pq = PriorityQueue()
    # pq.put('abc')
    # pq.put('def')
    #
    # print(pq.get())
    # print(pq.get())
  • 相关阅读:
    改善用户体念:jsp+Ajax实现实时上传,删除,导入Excel进度条
    hibernate+proxool的数据库连接池配置方法
    Js事件对象
    关于java数组拷贝的性能
    resin连接池配置
    java 动态编译源代码
    Java中对字符串进行加密和解密
    内存数据库H2 Mixed Mode布署
    ActiveX控件的另类免费签名法
    对PreparedStatement、Statement的一点总结
  • 原文地址:https://www.cnblogs.com/13507215809qwer-/p/9704003.html
Copyright © 2011-2022 走看看