是否可以将 ScopedValue 应用于“当前”StructuredTaskScope 而无需创建新任务?

问题描述 投票:0回答:1

我正在研究使用

ScopedValue
StructuredTaskScope
来替换 Google 的 gRPC 上下文的使用。

这两个系统都很好地不可变、轻量级并且支持嵌套作用域,但我认为 gRPC 上下文做了一些我需要的事情,而这些事情可能无法通过 ScopedValue 获得(如果属实,那将是一个真正的耻辱)。

在各种框架中,我可能需要在每个请求的基础上启用调试,如果请求匹配某些条件则打开附加日志记录。然而,我的代码永远无法包装某些函数以便将其嵌套在新任务中,它只是被调用并且必须在处理请求之前退出的代码。在伪代码中:

// Assume one handler per request.
class MyHandler implements SomeFrameworkCallbackApi {
    MyCloseable resetDebug = null;

    @Override
    void beforeRequest(RequestHeaders req, ConfigInfo info) {
        if (info.addLogging() && shouldDebug(req)) {
            Context newGrpcContext = Context.current().withValue(DEBUG_LEVEL, Level.FINE);
            Context prev = newGrpcContext.attach();
            resetDebug = () -> newGrpcContext.detach(prev);
        }
    }

    @Override
    void afterRequest(...) {
        if (resetDebug != null) {
            // Fails if not called in strict nesting order.
            resetDebug.close();
        }
    }
}

这让我即使在无法修改可以直接包装任务的代码的情况下也可以拥有作用域变量。

ScopedValue
StructuredTaskScope
的 API 来看,运行安装了
ScopedValue
的代码的唯一方法是调用
run()
等方法,这会强制对任务进行嵌套调用点(这在许多框架中是不可能的)。

我试过:

resetDebug = ScopedValue.getWhere(DEBUG_LEVEL, Level.FINE, StructuredTaskScope::new)::close;

但这会导致

java.util.concurrent.StructureViolationException
(不出意料)。

所以我的问题是,是否有其他方法可以使用

ScopedValue
(有或没有
StructuredTaskScope
)来实现我想要的目标,还是我需要继续使用 gRPC 上下文?

java java-21 structured-concurrency
1个回答
0
投票

来自布莱恩·戈茨:

“”这根本不是范围值的设计方式。您似乎想要的是 ThreadLocal 的无限制可变性,但具有 ScopedValue 的改进性能。但 ScopedValue 的好处来自于您似乎不喜欢的限制。""

所以答案很简单,

ScopedValue
只能用于通过直接包装代码来实现范围界定的情况,而不是使用在代码运行之前/之后发生的一些设置/拆卸回调。

在我的情况下(为可以从多种框架调用的库设置作用域值),我根本没有自由要求用户重构位于框架和我的库之间的代码来实现它们的所有范围都是通过直接包装代码来确定的。

如果您的需求与我的类似,那么

gRPC Context
提供了额外的功能,允许通过使用返回的
Closeable
来管理事物(例如使用 try-with-resources 设置范围)。

© www.soinside.com 2019 - 2024. All rights reserved.