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://zhangyanc.club/article/python_thread/
许可协议:署名-非商业性使用 4.0 国际许可协议