python 多线程的使用
多线程主要用于大量的IO操作时的并发执行,以此来提高效率!多进程主要用于大量的计算,进而充分发挥CPU的性能!
这里主要讲述两种多线程的使用:
- threading.Thread
- concurrent.futures.ThreadPoolExecutor
使用第二种方式需要先安装(对于python2.x)
pip install futures
基本使用
第一种方式的简单使用:(注意:空白行有删减)
# coding=utf8 import requests import threading import concurrent from concurrent.futures import ThreadPoolExecutor def task(): url = "https://www.baidu.com" res = requests.get(url) if res.status_code == 200: print "yes!" else: print "no!" def main(): t1 = threading.Thread(target=task) # 用法和Process类很相似 t2 = threading.Thread(target=task) t1.start() t2.start() t1.join() t2.join() if __name__ == '__main__': main()
多线程的同步
多线程的可以共享主线程的数据,在操作的时候可能会存在数据不同的问题解决办法是,对于一些代码加锁规定某段时间内只能一个线程访问,直到所被释放!
例子:这个会造成数据不同步
balance = 0 def data_operator(n): global balance # 表明在这个函数中,balance 是使用的全局的 balance += n balance -= n def change_it(n): for item in xrange(0, 10 ** 6): data_operator(n) def thread_synchronization(): t1 = threading.Thread(target=change_it, args=(5,)) t2 = threading.Thread(target=change_it, args=(8,)) t1.start() t2.start() t1.join() t2.join() global balance print balance # 因为存在变量操作时存在临时变量的使用,在多次执行的时候,操作的数据内容可能存在不同步的情况 # 所以此处打印出的值,不一定是0
加锁实现数据同步,确保操作关键数据时只有一个线程
balance = 0 main_thread_lock = threading.Lock() # 这里是在主线程中设置的一把线程锁 # 获得锁 main_thread_lock.acquire() 这个方法或阻塞当前线程,直到获得一把锁。但是不会阻塞主线程 # 释放锁 main_thread_lock.release() 此时其他的方法可以去申请锁的使用 # 一般使用try_catch_finally 来确保锁被释放 def data_operator(n): global balance # 表明在这个函数中,balance 是使用的全局的 balance += n balance -= n def change_it(n): for item in xrange(0, 10 ** 6): with main_thread_lock: # 这里是在操作主要数据的时候,获得锁,在执行完操作之后将锁释放,这里使用with 语句更加简洁的实现,一定要注意锁的释放 data_operator(n)
使用ThreadPoolExecutor
使用ThreadPoolExecutor的时候,对于python2.x 需要先安装 pip install futures ,这是在python3中自带的包
基本使用:
import concurrent from concurrent.futures import ThreadPoolExecutor def task2(n): url = "https://www.baidu.com" res = requests.get(url) print n if res.status_code == 200: return "yes!" else: return "no!" def multi_thread_by_thread_pool_executor(): # max_workers 最多使用的线程数量 with ThreadPoolExecutor(max_workers=5) as executor: task_list = [executor.submit(task2, x) for x in range(0, 10)] # 对结果的处理,as_completed 返回一个生成器,等待每一个任务完成的时候就会返回一个任务,参数是futures序列 # item 表示的是Future对象 # 使用 future.result 获取函数结果 for item in concurrent.futures.as_completed(task_list): print item.result()
不仅仅是对于线程有ThreadPoolExecutor, 对于进程而言,也就ProcessPoolExecutor,使用方式类似,只不过是名字改改
同时由于全局解释器锁的原因,即使很多的线程,CPU 也不能跑满,处分重构解释器,去掉GIL