多线程与多进程的优缺点 与 线程的一些方法

多进程:

  优点:可以用多核

  缺点:开销大

多线程:

  优点:开销小

  缺点:不能使用多核

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

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

  在这个时候我要提出一个观点:就是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('\033[32m%s 正在上厕所\033[0m ' % currentThread().name)
    time.sleep(random.randint(1, 3))
    print('\033[30%s 走出了厕所\033[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())
优先级锁

 

posted @ 2017-08-30 16:21  Python界-黄药师  阅读(2614)  评论(0编辑  收藏  举报