建设三类人员报考网站,网站内容管理,哈尔滨的网站设计,做的网站适应屏幕大小假设我们必须多线程任务创建大量线程。 由于线程太多#xff0c;因此可能会有很多性能问题#xff0c;这在计算上会是最昂贵的。 一个主要问题可能是吞吐量受限。 我们可以通过创建一个线程池来解决这个问题。 一个线程池可以被定义为一组预先实例化和空闲的线程#xff0c;…假设我们必须多线程任务创建大量线程。 由于线程太多因此可能会有很多性能问题这在计算上会是最昂贵的。 一个主要问题可能是吞吐量受限。 我们可以通过创建一个线程池来解决这个问题。 一个线程池可以被定义为一组预先实例化和空闲的线程它们随时可以开始工作。 创建线程池比我们需要执行大量任务时为每个任务实例化新线程更受欢迎。 线程池可以管理大量线程的并发执行如下所示 -
如果线程池中的线程完成其执行那么该线程可以被重用。如果一个线程被终止另一个线程将被创建以替换该线程。
Python模块 - Concurrent.futures
Python标准库包含concurrent.futures模块。 这个模块是在Python 3.2中添加的为开发人员提供了启动异步任务的高级接口。 它是Python的线程和多处理模块的顶层的一个抽象层用于提供使用线程或进程池运行任务的接口。 在后面的章节中我们将学习concurrent.futures模块中的类。
执行者类
Executor是一个 Python concurrent.futures模块的抽象类。 它不能直接使用我们需要使用以下具体子类之一 -
ThreadPoolExecutorProcessPoolExecutor
ThreadPoolExecutor -
一个具体的子类它是Executor类的具体子类之一。 子类使用多线程我们得到一个提交任务的线程池。 该池将任务分配给可用线程并安排它们运行。
如何创建一个ThreadPoolExecutor
在concurrent.futures模块及其具体子类Executor的帮助下可以很容易地创建一个线程池。 需要使用我们想要的池中的线程数构造一个ThreadPoolExecutor。 默认情况下数字是5。然后可以提交一个任务到线程池。 当submit()任务时会返回Future对象。 Future对象有一个名为done()的方法它告诉Future是否已经解决。 有了这个为这个特定的Future对象设定了一个值。 当任务完成时线程池执行器将该值设置为Future的对象。 示例代码
from concurrent.futures import ThreadPoolExecutor
from time import sleep
def task(message):sleep(2)return messagedef main():executor ThreadPoolExecutor(5)future executor.submit(task, (Completed))print(future.done())sleep(2)print(future.done())print(future.result())
if __name__ __main__:
main()
执行上面示例代码得到以下结果 -
False
True
Completed在上面的例子中一个ThreadPoolExecutor已经由5个线程构造而成。 然后在提供消息之前等待2秒的任务被提交给线程池执行器。 从输出中可以看出任务直到2秒才完成所以第一次调用done()将返回False。 2秒后任务完成我们通过调用result()方法得到future的结果
实例化ThreadPoolExecutor
上下文管理器另一种实例化ThreadPoolExecutor的方法是在上下文管理器的帮助下完成的。 它的工作方式与上例中使用的方法类似。 使用上下文管理器的主要优点是它在语法上看起来不错。 实例化可以在下面的代码的帮助下完成 -
with ThreadPoolExecutor(max_workers 5) as executor示例
以下示例是从Python文档借用的。 在这个例子中首先必须导入concurrent.futures模块。 然后创建一个名为load_url()的函数它将加载请求的url。 然后该函数用池中的5个线程创建ThreadPoolExecutor。 ThreadPoolExecutor已被用作上下文管理器。 我们可以通过调用result()方法来获得future的结果
import concurrent.futures
import urllib.requestURLS [http://www.foxnews.com/,https://www.yiibai.com/,http://europe.wsj.com/,http://www.bbc.co.uk/,http://some-made-up-domain.com/]def load_url(url, timeout):with urllib.request.urlopen(url, timeout timeout) as conn:return conn.read()with concurrent.futures.ThreadPoolExecutor(max_workers 5) as executor: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)))以下将是上面的Python脚本的输出 -
http://some-made-up-domain.com/ generated an exception: urlopen error [Errno 11004] getaddrinfo failed
http://www.foxnews.com/ page is 229313 bytes
http://www.yiibai.com/ page is 168933 bytes
http://www.bbc.co.uk/ page is 283893 bytes
http://europe.wsj.com/ page is 938109 bytes使用Executor.map()
函数Python map()函数广泛用于许多任务。 一个这样的任务是对可迭代内的每个元素应用某个函数。 同样可以将迭代器的所有元素映射到一个函数并将这些作为独立作业提交到ThreadPoolExecutor之外。 考虑下面的Python脚本示例来理解函数的工作原理。
示例
在下面的示例中map函数用于将square()函数应用于values数组中的每个值。
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed
values [2,3,4,5]
def square(n):return n * n
def main():with ThreadPoolExecutor(max_workers 3) as executor:results executor.map(square, values)for result in results:print(result)
if __name__ __main__:main()以下将是上面的Python脚本的输出 -
4
9
16
25