异步调用的困难之处我们不知道它什么时候会返回,通常的解决方法是使用回调来通知异步调用的结束。在大部分情况下,回调这种方式工作得很好,但是当异步调用太多时,太多的回调会将代码弄得很乱,同时很难跟踪代码执行过程。另外,它也使得在同步调用和异步调用之间切换变得困难。Java中有Future的概念,它封装了一个Callable对象,调用Future的get方法,不管Callable是异步调用还是同步调用,它都会一直等到Callable执行结束。这种方式的好处是程序不再管调用是异步还是同步的,从而极大地简化代码。Future通常是由Executor来创建的,Executor抽象任务的调度过程,是在调用线程中执行,或是另起一个线程,甚至另起一个进程,这些用户都不必关心。
这里我要实现一个简单的ThreadedExecutor,它每次来一个任务(调用它的submit方法)都起一个线程去执行,并立即返回一个Future对象,对Future对象调用result方法会一直等待任务执行结束,并返回执行结果。先从客户端代码写起:
import futures
import urllib2
def load_url(url, timeout):
return urllib2.urlopen(url, timeout=timeout).read()
executor = futures.ThreadedExecutor()
future = executor.submit(load_url, 'http://www.baidu.com', 60)
result = future.result()
print 'result: %s' % result
print 'OK'
上面的代码会另起一个线程抓取百度首页并将结果打印出来,但是从代码上看不到任何线程相关的代码(除了ThreadedExecutor这个名字暗示了可能有另外的线程执行),整个调用看起来就像同步调用。先看ThreadedExecutor的实现:
class ThreadedExecutor(object):
def submit(self, target, *args, **kwargs):
future = Future()
# always start a new thread
thread = threading.Thread(target=_Task(future, target, *args, **kwargs))
thread.start()
return future
ThreadedExecutor的submit方法只是创建一个Future对象,然后创建一个_Task对象,启动另一个线程运行它。
class _Task(object):
def __init__(self, future, target, *args, **kwargs):
self.future = future
self.target = target
self.args = args
self.kwargs = kwargs
def __call__(self):
try:
value = self.target(*self.args, **self.kwargs)
self.future._set_result(value)
except:
import sys
self.future._set_error(sys.exc_info()[0])
_Task对象本身是callable的,因为它实现了__call__方法,因而可以直接传递给线程。它就是简单地执行客户端的任务,完成之后将结果设置到future当中,注意__call__方法会捕捉所以异常,这是为了保证调用future的result()方法时程序总能结束。
class Future(object):
def __init__(self):
self._event = threading.Event()
self._result = None
self._error_happened = False
self._error = None
def result(self):
self._event.wait()
if self._error_happened:
raise self._error
return self._result
def _set_result(self, result):
self._result = result
self._event.set()
def _set_error(self, error):
self._error = error
self._error_happened = True
self._event.set()
Future这里关键是使用Event来协调线程之间的协作, 当调用result()方法时会先调用event的wait方法,它会一直等待直到event的set方法被调用,而只有客户提交的任务结束时才会调用,其总体效果就是result()就是只有当任务执行完成后才会返回。
另外,python3中已经对future已经有
内置实现,对python2可以使用
这个。
(完)
分享到:
相关推荐
本项目"Android-Future基于Kotlin协同程序的简单的monadic未来实现"旨在提供一个轻量级的、面向未来的异步处理框架,以帮助开发者更方便地处理并发任务。 首先,让我们深入理解什么是"Future"。在编程领域,Future...
Java中的Runnable、Callable、Future和FutureTask是Java多线程编程中的核心概念,它们各自扮演着不同的角色,共同协作以实现并发任务的管理和执行。 1. **Runnable**: Runnable是最基本的多线程接口,它只有一个`...
下面是一个简单的Future使用示例: ```java ExecutorService executor = Executors.newFixedThreadPool(1); Callable<Integer> task = () -> { Thread.sleep(1000); // 模拟耗时操作 return 42; // 返回结果 }; ...
本项目是用C++编程语言实现的一个简单邮件发送系统,旨在帮助用户通过程序化的方式发送和接收邮件,甚至包括邮件附件。 在C++中实现SMTP邮件系统涉及的关键知识点包括: 1. **网络编程基础**:使用C++进行网络编程...
Future1.0是一款专为IT企业设计的集成化项目管理系统,它利用Web技术,实现了跨地域、多团队的协同工作,旨在提升项目管理的效率和效果。系统提供了全面的项目管理功能,包括但不限于需求管理、任务分配、进度跟踪、...
下面是一个简单的例子,展示了如何使用`Future`来异步计算结果: ```java ExecutorService executor = Executors.newFixedThreadPool(1); Future<Integer> future = executor.submit(new Callable() { @Override ...
总结一下,`Runnable`用于无返回值的简单任务,`Callable`用于有返回值的任务,`Future`作为结果的容器,而`FutureTask`则将两者结合,使得`Callable`的任务可以通过`ExecutorService`执行。在实际开发中,根据需求...
CallableFuture 是 Future 的实现,仅当使用参数调用 .call(U arg) 方法时才返回 .get() 中的值。 这使得 CallableFuture 可用于通知单独线程中的代码关于另一个线程的工作结果。 创建它: final CallableFuture...
通过对比其他并发模式,我们可以看到Future在实现高效并发和保持代码简洁性方面具有显著优势,尤其是结合其衍生形态如Lazy Future,可以进一步优化资源利用率和程序设计。对于处理异步任务和并发编程的Java开发者来...
在Java中,`Future`和`ExecutorService`可以用来实现异步调用。`ExecutorService`是一个线程池服务,可以管理多个线程,而`Future`则用于获取异步任务的结果。 例如,下面是一个简单的异步调用示例: ```java ...
### 未来事物的设计 #### 一、概述 《未来事物的设计》是由唐纳德·A·诺曼(Donald...它让我们意识到,在这个快速变化的时代里,只有不断地学习新知识、掌握新技术,并将其应用于实践当中,才能真正实现设计的价值。
使用python-future实现Python 2/3兼容性的著名项目是和 。特征future.builtins包(也可以在Py2上以builtins形式提供)为Py3与Py2上具有不同语义的20个内置提供反向移植和重新映射。 支持直接在Py2上以其Pyth
继承Thread类和实现Runnable接口是基础,适用于简单场景;而ExecutorService、Callable和Future的组合则提供了更高级的功能,如线程池管理、异步计算和结果获取,适用于复杂并发环境。在实际开发中,合理利用这些...
在 Java 中,Future 模式可以使用 ExecutorService 和 Callable 实现。下面是一个简单的示例代码: ```java ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor....
例如,一个简单的实现Runnable接口的小程序可能如下所示: ```java public class MyRunnable implements Runnable { @Override public void run() { // 这里编写线程执行的代码 System.out.println("线程正在...
通过以上步骤,你可以使用Java轻松实现简单的截屏功能。这只是基本操作,实际应用中可能还需要考虑更多的细节,比如错误处理、多显示器支持、图像质量设置等。总的来说,Java的Robot类为开发者提供了一种强大且灵活...
在Java中,实现多线程有四种主要方法:继承Thread类、实现Runnable接口、使用ExecutorService和使用Callable与Future。下面将详细探讨这四种方式。 1. 继承Thread类 在Java中,我们可以直接继承Thread类并重写其run...
本文将深入探讨如何使用Java语言实现一个基本的网络爬虫,并结合`Future`接口,介绍多阶段流水线的异步执行机制。 首先,让我们了解网络爬虫的基础。一个简单的网络爬虫通常包括以下组件: 1. **URL管理器**:存储...
下面是一个使用`@Async`和`Future`的简单示例: ```java @Slf4j @Component public class Task { public static Random random = new Random(); @Async("taskExecutor") public Future<String> run() throws ...
为了更好地理解 `Future` 的工作原理,让我们通过一个简单的例子来深入探讨。 假设我们需要创建一个定时器 `Future`,该 `Future` 在经过指定的时间后返回一个结果。为此,我们可以定义一个结构体 `TimerFuture`,...