python 多线程,详细教程,线程同步,线程加锁,ThreadPoolExecutor

python 多线程的使用

多线程主要用于大量的IO操作时的并发执行,以此来提高效率!多进程主要用于大量的计算,进而充分发挥CPU的性能!

这里主要讲述两种多线程的使用:

  1. threading.Thread
  2. 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

你可能感兴趣的:(python)