当前位置: 首页 > 面试题库 >

将异步计算包装为同步(阻塞)计算

傅胡媚
2023-03-14
问题内容

我有一个对象,该对象带有一种方法,希望以类似以下方式向库客户端(尤其是脚本客户端)公开:

interface MyNiceInterface
{
    public Baz doSomethingAndBlock(Foo fooArg, Bar barArg);
    public Future<Baz> doSomething(Foo fooArg, Bar barArg);
    // doSomethingAndBlock is the straightforward way;
    // doSomething has more control but deals with
    // a Future and that might be too much hassle for
    // scripting clients
}

但是我可以使用的原始“东西”是一组事件驱动的类:

interface BazComputationSink
{
    public void onBazResult(Baz result);
}

class ImplementingThing
{
    public void doSomethingAsync(Foo fooArg, Bar barArg, BazComputationSink sink);
}

在其中,ImplementingThing接受输入,执行一些不可思议的工作,例如将任务排队入队列,然后稍后在发生结果时,sink.onBazResult()在可能与调用ImplementingThing.doSomethingAsync()相同的线程上调用该线程。

有没有一种方法可以使用我拥有的事件驱动功能以及并发原语来实现MyNiceInterface,以便脚本客户端可以愉快地等待阻塞线程?

编辑:
我可以为此使用FutureTask吗?


问题答案:

使用您自己的Future实现:

public class BazComputationFuture implements Future<Baz>, BazComputationSink {

    private volatile Baz result = null;
    private volatile boolean cancelled = false;
    private final CountDownLatch countDownLatch;

    public BazComputationFuture() {
        countDownLatch = new CountDownLatch(1);
    }

    @Override
    public boolean cancel(final boolean mayInterruptIfRunning) {
        if (isDone()) {
            return false;
        } else {
            countDownLatch.countDown();
            cancelled = true;
            return !isDone();
        }
    }

    @Override
    public Baz get() throws InterruptedException, ExecutionException {
        countDownLatch.await();
        return result;
    }

    @Override
    public Baz get(final long timeout, final TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
        countDownLatch.await(timeout, unit);
        return result;
    }

    @Override
    public boolean isCancelled() {
        return cancelled;
    }

    @Override
    public boolean isDone() {
        return countDownLatch.getCount() == 0;
    }

    public void onBazResult(final Baz result) {
        this.result = result;
        countDownLatch.countDown();
    }

}

public Future<Baz> doSomething(Foo fooArg, Bar barArg) {
    BazComputationFuture future = new BazComputationFuture();
    doSomethingAsync(fooArg, barArg, future);
    return future;
}

public Baz doSomethingAndBlock(Foo fooArg, Bar barArg) {
    return doSomething(fooArg, barArg).get();
}

该解决方案在内部创建一个CountDownLatch,一旦收到回调,该计数器将被清除。如果用户调用get,则使用CountDownLatch阻止调用线程,直到计算完成并调用onBazResult回调。CountDownLatch将确保如果回调在调用get()之前发生,则get()方法将立即返回结果。



 类似资料:
  • MXNet使用异步计算来提升计算性能。理解它的工作原理既有助于开发更高效的程序,又有助于在内存资源有限的情况下主动降低计算性能从而减小内存开销。我们先导入本节中实验需要的包或模块。 from mxnet import autograd, gluon, nd from mxnet.gluon import loss as gloss, nn import os import subproces

  • 本文向大家介绍请你说一下阻塞,非阻塞,同步,异步相关面试题,主要包含被问及请你说一下阻塞,非阻塞,同步,异步时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 阻塞和非阻塞:调用者在事件没有发生的时候,一直在等待事件发生,不能去处理别的任务这是阻塞。调用者在事件没有发生的时候,可以去处理别的任务这是非阻塞。 同步和异步:调用者必须循环自去查看事件有没有发生,这种情况是同步。调用者不用自己去查看

  • 从进程调度谈起 现代操作系统(如 Windows、Linux 等)都是分时系统。分时系统允许同时允许多个任务,但实际上,由于一台计算机通常只有一个 CPU,所以不可能真正地同时运行多个任务。这些进程实际上是轮番运行,每个进程运行一个时间片。由于时间片通常很短,用户不会感觉到,所以这些进程看起来就像是同时运行。 每个进程的时间片由操作系统完成初始化,所有进程轮番地执行相应的时间。具体下一个时间片轮到

  • 本文向大家介绍java 中同步、异步、阻塞和非阻塞区别详解,包括了java 中同步、异步、阻塞和非阻塞区别详解的使用技巧和注意事项,需要的朋友参考一下 java 中同步、异步、阻塞和非阻塞区别详解 简单点说: 阻塞就是干不完不准回来,一直处于等待中,直到事情处理完成才返回; 非阻塞就是你先干,我先看看有其他事没有,一发现事情被卡住,马上报告领导。 我们拿最常用的send和recv两个函数来说吧..

  • 我认为下面的流量链将通过事件循环放置/执行(像JS)。因此,运行下面的代码将首先打印阻塞循环&然后将执行通量链。 但是,整个通量总是先执行,然后才移动到循环。[我确实有一些语句正在阻塞。但是有两个阶段] 当我们使用reactor时,通过使用一些调度程序来实现异步/非阻塞行为的唯一方法? 如果我不使用任何调度器,并让代码使用当前线程执行,那么即使对于IO密集型应用程序,使用WebFlux而不是Spr

  • 本文向大家介绍详解socket阻塞与非阻塞,同步与异步、I/O模型,包括了详解socket阻塞与非阻塞,同步与异步、I/O模型的使用技巧和注意事项,需要的朋友参考一下 socket阻塞与非阻塞,同步与异步 1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步: 所谓同步,就是在