Python基础(8) 多线程

0. 前言

  • 目标:实现多线程并发执行程序。
  • 特点:
    • 由全局解释器锁于(Global Interpreter Lock,GIL)的存在,多线程执行程序只能占用一个CPU核。
    • 换句话说,Python多线程不适用于CPU密集型任务,但适用于IO密集型任务
    • 当使用CPU密集型任务时,应该使用Python多进程
  • 相关包
    • threading 模块
    • concurrent 模块

1. threading 模块

  • 主要是对单个线程的操作,即以 threading.Thread 为基础。

1.1. Thread 对象

  • 定义:threading.Thread(name="thread_name", daemon=None, target=None)
  • 主要方法:
    • start():启动线程,会自动调用 run 方法。
    • run()
      • 一般自己实现实现线程时会重写该方法。
      • 但在默认情况下,可以通过设置 target 参数来传入需要执行的方法。
    • is_alive():线程是否还在运行中。
    • join(timeout=None):在A的线程中调用B线程的该方法,则A线程会等待B线程执行完毕后再进行下一步操作。
    • 守护进程相关:
      • isDaemon():判断是否是守护进程。
      • daemon:作为参数,可以直接get/set。
    • name:作为参数,可以直接get/set。

1.2. 其他API

  • 包提供的方法:
    • active_count():活跃线程数量
    • current_thread():当前线程对象
    • get_ident():当前线程的idx,是一个非0数字
    • enumerate():遍历获取所有活跃线程
    • main_thread():主线程对象
  • 锁对象:Lock,对应 acquire/release 方法。
  • 还有很多暂时用不到的,不记录了。
    • RLock
    • Condition
    • Semaphore
    • Event
    • Timer
    • Barrier

2. concurrent.features 包

  • 不仅包含了线程池,也包含了进程池。
    • 本文不讲进程池相关内容。

2.1. 线程池

  • Executor
    • 是个抽象类,不直接使用,一般都用他的子类。
    • 子类包括了线程池 ThreadPoolExecutor 与进程池 ProcessPoolExecutor
    • 主要方法:
      • submit(fn, *args, **kwargs):调用 fn(*args, **kwargs) 并返回 Future 对象。
      • shutdown(wait=True):关闭线程池。
      • map(func, *iterables, timeout=None, chunksize=1):类似于 map 方法,我自己不怎么用所以不详细了解了。
  • ThreadPoolExecutor
    • Executor 的子类,主要方法也就是上面的三个。
  • Future 对象:
    • 线程池调用 submit 方法后得到的。
    • 对象用来获取提交的任务的运行状态。
    • 常用方法:
      • cancel():取消任务,成功取消返回True,否则返回False。
      • cancelled():判断是否取消。
      • running():判断是否正在执行。
      • done():判断是否运行结束(正常运行结束或cancel都算)。
      • result(timeout=None):获取调用结果,如果还没有运行结束则阻塞当前线程并等待结果,在规定时间内若还没有运行结束,则会出发异常。
      • exception(timeout=None):类似于result,获取调用引发的异常,正常运行结束则会返回None,若还没有运行结束则会等待一定时间。

2. 实例

  • 线程池的创建/删除可以手动实现,也可以通过 with 实现。
import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值