是否有螺纹安全的方法来记忆Kotlin序列?

发布于 2025-01-28 03:23:11 字数 1510 浏览 4 评论 0原文

我有一种生成序列的方法:

    fun createFactorSequence(decimalMode: DecimalMode): Sequence<BigDecimal> {
        var sign = BigDecimal.ZERO - BigDecimal.ONE
        return createAllFactorialsSequence()
            .filterIndexed { i, _ -> i % 2 != 0 }
            .map { n ->
                sign = -sign
                sign * BigDecimal.ONE.divide(n, decimalMode)
            }
    }

因为多个调用之间的序列将相同,所以似乎应该可以缓存它(我必须按照当前形式的小数模式来键入,但是可能会有是消除对此需求的方法。

我已经在野外看到了一些代码,这些代码试图实现一个记忆的序列,将基础序列的元素记录到列表中,以便下一个调用不需要重新计算它们。

它们主要沿着这些线路工作(我已经简化了它以假设序列是无限的):

    fun <T> memoizedSequence(slowSequence: Sequence<T>): Sequence<T> {
        val slowIterator = slowSequence.iterator()
        val cachedEntries = mutableListOf<T>()

        return sequence {
            var index = 0
            while (true) {
                // TODO: Not thread-safe!!
                while (cachedEntries.size < index) {
                    cachedEntries.add(slowIterator.next())
                }

                yield(cachedEntries[index])

                index++
            }
        }
    }

如所评论的那样,问题是这不是线程安全。如果两个线程同时通过,并且每个线程都会从迭代器中获得一个元素,则无法保证条目将以相同的顺序最终进入列表。

但是我不能仅仅使用java同步来解决它,因为库是乘数。

有Kotlin做到这一点吗?

我尝试使用mutex(我什至不确定是否可以接受对Coroutines的依赖),但发现我不允许我致电mutex.withlock从内部序列{}

I have a method which generates a sequence:

    fun createFactorSequence(decimalMode: DecimalMode): Sequence<BigDecimal> {
        var sign = BigDecimal.ZERO - BigDecimal.ONE
        return createAllFactorialsSequence()
            .filterIndexed { i, _ -> i % 2 != 0 }
            .map { n ->
                sign = -sign
                sign * BigDecimal.ONE.divide(n, decimalMode)
            }
    }

Because the sequence will be the same between multiple invocations, it seems like it should be possible to cache it (I would have to key that by the decimal mode, in its current form, but there may be ways to remove the need for that).

I have seen some code out in the wild which attempts to implement a memoized sequence, recording the elements from the underlying sequence into a list so that the next invocation wouldn't need to recompute them.

They mostly work along these lines (I've simplified it to assume the sequence is infinite):

    fun <T> memoizedSequence(slowSequence: Sequence<T>): Sequence<T> {
        val slowIterator = slowSequence.iterator()
        val cachedEntries = mutableListOf<T>()

        return sequence {
            var index = 0
            while (true) {
                // TODO: Not thread-safe!!
                while (cachedEntries.size < index) {
                    cachedEntries.add(slowIterator.next())
                }

                yield(cachedEntries[index])

                index++
            }
        }
    }

The problem, as commented, is that this is not thread-safe. If two threads come through at the same time and each get an element from the iterator, there's no guarantee that the entries will end up in the list in the same order.

But I can't just use Java synchronization to get around it, because the library is multiplatform.

Is there a Kotlin way to do this?

I attempted to use Mutex (I'm not even sure whether adding a dependency on coroutines is going to be acceptable) but found that I'm not allowed to call Mutex.withLock from inside sequence {}.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文