zoukankan      html  css  js  c++  java
  • 多线程

    线程和进程的区别:

    进程之间切换非常消耗资源

    线程之间切换相对来说节省资源

     

    使用线程的场景:

    多进程和多线程的数据共享的区别

    # 多进程  最后执行打印结果两个100
    from multiprocessing import Process
    def func1():
        global g
        g = 0
    
    if __name__ == '__main__':
        g = 100
        print(g)
        p = Process(target=func1)
        p.start()
        p.join()
        print(g)
    
    
    
    # 多线程  最后执行打印结果两个第一个100,第二个0
    from threading import Thread def func1(): global g g = 0 if __name__ == '__main__': g = 100 print(g) t = Thread(target=func1) t.start() t.join() print(g)

      

    全局解释锁GIL锁住的不是线程共享的数据,而是所有的进程。

    虽然有了全局解释锁GIL,但是还不是最安全的,因为比如以下情况:

    这种情况下我想着线程有了全局解释锁,最后结果应该是0,打印出来结果却是9,因为中间我们人为让程序睡眠了一秒(真实情况下可能由于时间片轮转到了下一个线程),

    所以这个时候就需要加锁了。

    科学家吃面引出来的死锁问题:

    from threading import Thread, Lock
    import time
    noodle_lock = Lock()
    fork_look = Lock()
    def eat1(name):
        noodle_lock.acquire()
        print("{}拿到面了".format(name))
        fork_look.acquire()
        print("{}拿到叉子了".format(name))
        print("{}开始吃面了".format(name))
        noodle_lock.release()
        fork_look.release()
    
    
    def eat2(name):
        fork_look.acquire()
        print("{}拿到叉子了".format(name))
        time.sleep(1)
        noodle_lock.acquire()
        print("{}拿到面了".format(name))
        print("{}开始吃面了".format(name))
        fork_look.release()
        noodle_lock.release()
    
    if __name__ == '__main__':
        Thread(target=eat1, args=("alex", )).start()
        Thread(target=eat2, args=("egon", )).start()
        Thread(target=eat1, args=("nezha", )).start()
        Thread(target=eat2, args=("bossjin", )).start()
    

      

    科学家吃面引出来的递归锁问题:

    from threading import Thread, RLock
    import time
    fork_look = noodle_lock = RLock()
    def eat1(name):
        noodle_lock.acquire()
        print("{}拿到面了".format(name))
        fork_look.acquire()
        print("{}拿到叉子了".format(name))
        print("{}开始吃面了".format(name))
        noodle_lock.release()
        fork_look.release()
    
    
    def eat2(name):
        fork_look.acquire()
        print("{}拿到叉子了".format(name))
        time.sleep(1)
        noodle_lock.acquire()
        print("{}拿到面了".format(name))
        print("{}开始吃面了".format(name))
        fork_look.release()
        noodle_lock.release()
    
    if __name__ == '__main__':
        Thread(target=eat1, args=("alex", )).start()
        Thread(target=eat2, args=("egon", )).start()
        Thread(target=eat1, args=("nezha", )).start()
        Thread(target=eat2, args=("bossjin", )).start()
    

      

     

    同一个进程或线程中用到两把或两把以上锁的时候,就容易产生死锁现象,这个时候把互斥锁改为递归锁,就能规避这种情况。

    RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

    进程中的数据本身就不共享,所以很少会用到加锁的情况,而线程则是数据共享的,所以需要加锁  

    线程中的事件例子:

    from threading import Thread, Event
    import random
    import time
    
    e = Event()
    
    def check_web():
        time.sleep(random.randint(3, 6))
        e.set()
    
    def conn_db():
        count = 1
        while count < 4:
            e.wait(1)
            if e.is_set():
                print("连接数据库成功")
                break
            else:
                print("第{}次连接数据库失败".format(count))
                count += 1
        else:
            raise TimeoutError("连接数据库超时")
    
    
    
    if __name__ == '__main__':
        Thread(target=check_web).start()
        Thread(target=conn_db).start()
    

      

    线程中的定时器

    from threading import Thread, Timer
    def func():
        print("五秒后的线程开启")
    
    if __name__ == '__main__':
        Timer(interval=5, function=func).start()
    

      

    线程池中的队列:

    # 多线程中的数据已经是共享的了,为什么还要用队列?
    # 比如a线程要修改共享的一个列表中的一个元素,刚拿回来数据准备修改,时间片到了b线程,
    # 这个时候b又去修改这个元素,就会造成数据的不安全,这个时候可以想到应该加锁,
    # 而队列中就是加好锁了,供我们使用。
    
    
    import queue
    q = queue.Queue()  #队列,先进先出
    q.put(1)
    q.put(2)
    print(q.get())
    
    
    q = queue.LifoQueue()  #栈,先进后出
    q.put(1)
    q.put(2)
    print(q.get())
    
    
    q = queue.PriorityQueue()  #优先级队列
    q.put((10, "a"))
    q.put((1, "b"))
    q.put((8, "c"))
    print(q.get())
    

      

    线程池

    # 线程池里面的线程个数最多不要超过cpu个数乘以五
    from concurrent.futures import ThreadPoolExecutor
    import time
    
    
    def func(n):
        print(n)
        time.sleep(1)
        return n * n
    
    if __name__ == '__main__':
        pool = ThreadPoolExecutor(max_workers=5)
        for i in range(1, 21):
            p = pool.submit(func, i)
        pool.shutdown() #shutdown起到了close和join两个效果,close不让往线程池中扔任务,join等待线程池中的任务执行完毕
        print("主线程")
    

      

  • 相关阅读:
    Spring基础知识
    Hibernate基础知识
    Struts2基础知识
    在eclipse里头用checkstyle检查项目出现 File contains tab characters (this is the first instance)原因
    java后台获取cookie里面值得方法
    ckplayer 中的style.swf 中的 style.xml 中的修改方法
    java hql case when 的用法
    Windows下Mongodb安装及配置
    Mongodb中经常出现的错误(汇总)child process failed, exited with error number
    Mac 安装mongodb
  • 原文地址:https://www.cnblogs.com/QimiSun/p/10578002.html
Copyright © 2011-2022 走看看