zoukankan      html  css  js  c++  java
  • 多线程与多进程的优缺点 与 线程的一些方法

    多进程:

      优点:可以用多核

      缺点:开销大

    多线程:

      优点:开销小

      缺点:不能使用多核

      在日常的生活中,我们用到的肯定是多核机器,所以我们只考虑多核的情况,你会说那么根据上面的优缺点,那肯定就用多进程就好了。欧克,那只是你自己的意淫而已,接下来我要解释一波了,请听好:

      我们首先确定的点,就是在一个多核的机器上,进行一系列的操作,那么使用多线程好呢?还是多进程好呢?

      在这个时候我要提出一个观点:就是CPU肯定是用来做计算的,这是毋庸置疑的。

      ok,我们在之前的基础上,考虑两种情况:

      1,计算密集的操作:我用代码来征服你们,看哪一个更好

      

    from multiprocessing import Process
    import time
    def work():
        res = 0
        for i in range(11111100):
            res+=i
    if __name__ == '__main__':
        start = time.time()
        l = []
        for i in range(4):
            p = Process(target=work)
            l.append(p)
            p.start()
        for j in l:
            j.join()
        end = time.time()
        print('%s'%(end - start))
    
    运行时间:1.794102430343628 #根据机子的不同可能结果也并不同
    多进程
    from threading import Thread
    
    import time
    def work():
        res = 0
        for i in range(11111100):
            res+=i
    if __name__ == '__main__':
        start = time.time()
        l = []
        for i in range(4):
            T = Thread(target=work)
            l.append(T)
            T.start()
        for j in l:
            j.join()
        end = time.time()
        print('%s'%(end - start))
    
    结果:3.125178813934326
    多线程

      看结果一目了然,进程很快,你很牛逼,我来说说原理:对于多线程来说,上面已经提到,他的缺点就是无法使用多核,由于gil锁的存在,他只能一个一个的取抢锁,所以会慢,多进程则相反

      2,i/o密集的操作:依旧用代码来征服你:

    from threading import Thread
    
    import time
    
    
    def work():
        time.sleep(2)
    
    
    if __name__ == '__main__':
        start = time.time()
        l = []
        for i in range(400):
            p = Thread(target=work)
            # p = Process(target=work)
            l.append(p)
            p.start()
        for j in l:
            j.join()
        end = time.time()
        print('%s' % (end - start))
    
    结果:2.048117160797119
    多线程
    from multiprocessing import Process
    
    
    import time
    
    
    def work():
        time.sleep(2)
    
    
    if __name__ == '__main__':
        start = time.time()
        l = []
        for i in range(400):
            # p = Thread(target=work)
            p = Process(target=work)
            l.append(p)
            p.start()
        for j in l:
            j.join()
        end = time.time()
        print('%s' % (end - start))
    
    结果:from multiprocessing import Process
    from threading import Thread
    
    import time
    
    
    def work():
        time.sleep(2)
    
    
    if __name__ == '__main__':
        start = time.time()
        l = []
        for i in range(400):
            # p = Thread(target=work)
            p = Process(target=work)
            l.append(p)
            p.start()
        for j in l:
            j.join()
        end = time.time()
        print('%s' % (end - start))
    
    结果:19.68112564086914
    多进程

    看结果很明显:我用时间的停留模拟i/o阻塞,进程确实是并发的,但是在i/o阻塞的时候都要等着,无法运行,并且在进程创建的时候开销大,时间长,即使是并发的,我开了400个进程,机已经多出了那么多的时间,可想而知,开更多会是什么样。

    应用:

    计算密集 多进程 金融领域

    i/o密集 多线程  爬虫 web socket

    死锁 与递归锁、

    所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,情况如下:

    from threading import Thread,Lock
    import time
    mutexA = Lock()
    mutexB = Lock()
    
    
    class Work(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print('%s 拿到了A锁 ' % self.name)
            mutexB.acquire()
            print('%s拿到了B锁' % self.name)
            mutexB.release()
            print('%s 释放了 B锁' % self.name)
            mutexA.release()
            print('%s 释放了 A锁' % self.name)
    
        def f2(self):
            mutexB.acquire()
            time.sleep(2)
            print('%s 拿到了B锁 ' % self.name)
            mutexA.acquire()
            print('%s拿到了A锁' % self.name)
            mutexA.release()
            print('%s 释放了 A锁' % self.name)
            mutexB.release()
            print('%s 释放了 B锁' % self.name)
    
    if __name__ == '__main__':
        for i in range(5):
            t = Work()
            t.start()

    解决方法:

    递归锁:Rlock

    Rlock内部有一个count 初始为0 ,锁一下加1,释放了就减一。

    from threading import Thread,RLock
    import time
    mutexA = mutexB = RLock()
    class Work(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print('%s 拿到了A锁 ' % self.name)
            mutexB.acquire()
            print('%s拿到了B锁' % self.name)
            mutexB.release()
            print('%s 释放了 b锁' % self.name)
            mutexA.release()
            print('%s 释放了 a锁' % self.name)
    
        def f2(self):
            mutexB.acquire()
            time.sleep(2)
            print('%s 拿到了A锁 ' % self.name)
            mutexA.acquire()
            print('%s拿到了B锁' % self.name)
            mutexA.release()
            print('%s 释放了 b锁' % self.name)
            mutexB.release()
            print('%s 释放了 a锁' % self.name)
    
    if __name__ == '__main__':
        for i in range(5):
            t = Work()
            t.start()
    递归锁

    信号量Semaphore 他是一种锁 

    Semaphore ()括号内的参数是几,就说明可以有几个可以用这段锁中的代码,并不是同事哦 谁先运行完,下一个就会进来。

    信号量与进程池是有着同一种的用途,但是用法不同,很且差很多

    from threading import Thread, Semaphore, currentThread
    import time,random
    sm = Semaphore(5)
    
    
    def work():
        sm.acquire()
        print('33[32m%s 正在上厕所33[0m ' % currentThread().name)
        time.sleep(random.randint(1, 3))
        print('33[30%s 走出了厕所33[0m' % currentThread().name)
        sm.release()
    if __name__ == '__main__':
        for i in range(20):
            t = Thread(target=work,)
            t.start()
    信号量

    Event

    线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行

    Event的一些方法:

    event = Event()

    event.isSet():返回event的状态值;
    
    event.wait():如果 event.isSet()==False将阻塞线程;
    
    event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
    
    event.clear():恢复event的状态值为False。

    具体应用在mysql中
    from threading import Thread, Event, currentThread
    import time
    
    def check_mysql():
        print('%s 正在检测mysql... ' % currentThread().name)
        time.sleep(4)
        e.set()
    
    
    def conn_mysql():
        count = 1
        while not e.is_set():
            if count > 4:
                raise ConnectionResetError('链接次数过多')
            print('%s 正在等待第%s链接mysql' % (currentThread().name, count))
            e.wait(timeout=1)
            count += 1
        print('%s 连接成功' % currentThread().name)
    if __name__ == '__main__':
        traffic = Thread(target=check_mysql)
        traffic.start()
        for i in range(3):
            t = Thread(target=conn_mysql)
            t.start()
    666

    定时器

    from threading import Timer
     
     
    def hello():
        print("hello, world")
     
    t = Timer(1, hello)
    t.start()  # after 1 seconds, "hello, world" will be printed
    View Code

    线程queue

    import queue
    
    # q=queue.Queue(3) #先进先出
    # q.put('first')
    # q.put('second')
    # q.put('third')
    # # q.put('fourth')
    #
    # print(q.get())
    # print(q.get())
    # print(q.get())
    队列q
    # q=queue.LifoQueue() #先进后出
    # q.put('first')
    # q.put('second')
    # q.put('third')
    # # q.put('fourth')
    #
    # print(q.get())
    # print(q.get())
    # print(q.get())
    堆栈q
    import queue
    
    q=queue.PriorityQueue()
    #put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
    q.put((20,'a'))
    q.put((10,'b'))
    q.put((30,'c'))
    
    print(q.get())
    print(q.get())
    print(q.get())
    优先级锁
    最新免费视频: http://www.pythonav.com/all/10000.html
  • 相关阅读:
    前缀和(题目)
    面向对象的程序设计_第一次作业 3月12日
    搜索(题目)
    牛客算法周周练3 B--「木」迷雾森林(dp记忆化搜索+快速读入模板)
    牛客算法周周练3 D--表达式求值(stack)
    [NOIP2012]同余方程(拓展欧几里得)
    欧几里得算法和拓展欧几里得
    Educational Codeforces Round 86 (Rated for Div. 2)
    “Shopee杯” e起来编程暨武汉大学2020年大学生程序设计大赛决赛(重现赛)A--A Simple Problem about election(模拟)
    “Shopee杯” e起来编程暨武汉大学2020年大学生程序设计大赛决赛(重现赛)F--Figure out the sequence(map)
  • 原文地址:https://www.cnblogs.com/niehaidong111/p/7453718.html
Copyright © 2011-2022 走看看