multiprocessing是python封装的包含了调用和进程间通讯的多进程类库, 无论密集型运算还是IO堵塞都能用, 副作用小, 但最重。
threading是基于系统级的线程调用, 适用的场合通常是IO堵塞。多线程的优势是切换快资源消耗低,但一个线程挂掉则会影响到所有线程,所以不够稳定。现实中使用线程池的场景会比较多gevent和asycio是基于协程的python网络库,在遇到IO阻塞时,程序会自动进行切换,可以让我们用同步的方式写异步IO代码。
总结: IO 密集型一般使用多线程或者多进程,CPU 密集型一般使用多进程,强调非阻塞异步并发的一般都是使用协程
多线程
因为有GIL的存在,所以Python中的多线程不能真正的利用多核,对于计算密集型的任务多线程是鸡肋的。但是对于IO密集型,例如爬虫,文件读写等多线程是完全可行的,因为网络IO的延迟比CPU的更大。
1.threading实例
如果要实现主线程和子线程的同步,我们必需使用join方法
import threading import time def long_time_task(i): print('当前子线程: {} 任务{}'.format(threading.current_thread().name, i)) time.sleep(2) print("结果: {}".format(8 ** 20)) if __name__=='__main__': start = time.time() print('这是主线程:{}'.format(threading.current_thread().name)) thread_list = [] for i in range(1, 3): t = threading.Thread(target=long_time_task, args=(i, )) thread_list.append(t) t.start() for t in thread_list: t.join() end = time.time() print("总共用时{}秒".format((end - start))) >>> 这是主线程:MainThread 当前子线程: Thread-1 任务1 当前子线程: Thread-2 任务2 结果: 1152921504606846976 结果: 1152921504606846976 总共用时2.001833915710449秒
2.继承Thread类重写run方法创建新线程
import threading import time def long_time_task(i): time.sleep(2) return 8**20 class MyThread(threading.Thread): def __init__(self, func, args , name='', ): threading.Thread.__init__(self) self.func = func self.args = args self.name = name self.result = None def run(self): print('开始子进程{}'.format(self.name)) self.result = self.func(self.args[0],) print("结果: {}".format(self.result)) print('结束子进程{}'.format(self.name)) if __name__=='__main__': start = time.time() threads = [] for i in range(1, 3): t = MyThread(long_time_task, (i,), str(i)) threads.append(t) t.start() for t in threads: t.join() end = time.time() print("总共用时{}秒".format((end - start))) >>> 开始子进程1 开始子进程2 结果: 1152921504606846976 结果: 1152921504606846976 结束子进程2 结束子进程1 总共用时2.0016472339630127秒
3.使用线程锁
一个进程所含的不同线程间共享内存,这就意味着任何一个变量都可以被任何一个线程修改,因此线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。如果不同线程间有共享的变量,其中一个方法就是在修改前给其上一把锁lock,确保一次只有一个线程能修改它。threading.lock()方法可以轻易实现对一个共享变量的锁定,修改完后release供其它线程使用
import threading class Account: def __init__(self): self.balance = 0 def add(self, lock): # 获得锁 lock.acquire() for i in range(0, 100000): self.balance += 1 # 释放锁 lock.release() def delete(self, lock): # 获得锁 lock.acquire() for i in range(0, 100000): self.balance -= 1 # 释放锁 lock.release() if __name__ == "__main__": account = Account() lock = threading.Lock() # 创建线程 thread_add = threading.Thread(target=account.add, args=(lock,), name='Add') thread_delete = threading.Thread(target=account.delete, args=(lock,), name='Delete') # 启动线程 thread_add.start() thread_delete.start() # 等待线程结束 thread_add.join() thread_delete.join() print('The final balance is: {}'.format(account.balance)) >>>The final balance is: 0
多进程
Python中的多进程是通过multiprocessing包来实现的,和多线程的threading.Thread差不多
1.Process实例化实现
from multiprocessing import Process def fun1(name): print('测试%s多进程' %name) if __name__ == '__main__': process_list = [] for i in range(5): #开启5个子进程执行fun1函数 p = Process(target=fun1,args=('Python',)) #实例化进程对象 p.start() process_list.append(p) for i in process_list: p.join() print('结束测试') >>> 测试Python多进程 测试Python多进程 测试Python多进程 测试Python多进程 测试Python多进程 结束测试
可以看到结果差不多是同时打印的,实现了真正的并行操作,就是多个CPU同时执行任务
2.继承Process类创建新进程
from multiprocessing import Process class MyProcess(Process): #继承Process类 def __init__(self,name): super(MyProcess,self).__init__() self.name = name def run(self): print('测试%s多进程' % self.name) if __name__ == '__main__': process_list = [] for i in range(5): #开启5个子进程执行fun1函数 p = MyProcess('Python') #实例化进程对象 p.start() process_list.append(p) for i in process_list: p.join() print('结束测试')
3.进程池
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。就是固定有几个进程可以使用。
from multiprocessing import Process,Pool import os, time, random def fun1(name): print('Run task %s (%s)...' % (name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print('Task %s runs %0.2f seconds.' % (name, (end - start))) if __name__=='__main__': pool = Pool(5) #创建一个5个进程的进程池 for i in range(10): pool.apply_async(func=fun1, args=(i,)) pool.close() pool.join() print('结束测试')
版权声明:如无特殊说明,文章均为本站原创,转载请注明出处
本文链接:http://example.com/article/python_thread/