了解供应点块(按需供应)

2024-01-04

我无法理解我的目的supply {…}他们创建的块/按需供应。

Live供应(即来自Supplier并在任何时候获得新的值Supplier发出一个值)对我来说很有意义——它们是异步流的一种版本,我可以用它来将消息从一个或多个发送者广播到一个或多个接收者。很容易看到响应实时消息流的用例:每次从 GUI 界面获取 UI 事件时,或者每次聊天应用程序广播它已收到新消息 https://cro.services/docs/reference/cro-http-router-websocket#Basic_usage.

But 一经请求供应没有同样的意义。这docs https://docs.raku.org/language/concurrency#Supplies比如说

点播广播就像 Netflix:每个开始流式传输电影(点击供应)的人总是从头开始(获取所有值),无论现在有多少人正在观看。

好,可以。但为什么/什么时候我需要这些语义呢?

这些例子也让我有点摸不着头脑。 Concurancy 页面当前提供了三个示例supply块,但其中两个只是发出来自 a 的值for环形。第三个是一个更详细一点 https://docs.raku.org/language/concurrency#whenever:

my $bread-supplier = Supplier.new;
my $vegetable-supplier = Supplier.new;
 
my $supply = supply {
    whenever $bread-supplier.Supply {
        emit("We've got bread: " ~ $_);
    };
    whenever $vegetable-supplier.Supply {
        emit("We've got a vegetable: " ~ $_);
    };
}
$supply.tap( -> $v { say "$v" });
 
$vegetable-supplier.emit("Radish");   # OUTPUT: «We've got a vegetable: Radish␤» 
$bread-supplier.emit("Thick sliced"); # OUTPUT: «We've got bread: Thick sliced␤» 
$vegetable-supplier.emit("Lettuce");  # OUTPUT: «We've got a vegetable: Lettuce␤» 

在那里,supply块正在做某事。具体来说,它对两个不同(实时)的输入做出反应Suppliers,然后将它们合并成一个Supply。这看起来确实相当有用。

…除了如果我想转换两个的输出Suppliers 并将它们的输出合并到一个组合流中,我可以使用

my $supply = Supply.merge: 
                 $bread-supplier.Supply.map(    { "We've got bread: $_" }),
                 $vegetable-supplier.Supply.map({ "We've got a vegetable: $_" });

事实上,如果我更换supply在该示例中使用块map/merge上面,我得到了完全相同的输出。此外,既不supply块版本也不map/merge如果版本产生任何输出tap被移动到调用下方.emit,这表明“按需”方面supply块在这里并没有真正发挥作用。

在更一般的层面上,我不相信 Raku(或Cro https://cro.services/docs)文档提供了任何示例supply块也不以某种方式改变现场的输出Supply或基于a发出值for循环或Supply.interval。除了作为一种不同的转型方式之外,这些似乎都不是特别引人注目的用例Supplys.

鉴于上述所有情况,我很想大部分注销supply块作为一个构造并没有那么有用,除了作为某些可能的替代语法Supply组合器。不过,我有它相当好的权威 https://stackoverflow.com/a/69369210/10173009

虽然经常会联系供应商,但很多时候最好编写一个发出值的供应块。

鉴于此,我愿意冒险一个非常有信心的猜测,我失踪了某物 about supply块。如果您能了解这可能是什么,我将不胜感激。


鉴于你提到Supply.merge,让我们从那开始吧。想象一下,它不在 Raku 标准库中,而我们必须实现它。为了达到正确的实施,我们必须注意什么?至少:

  1. 制作一个Supply结果是,当点击时,会...
  2. 点击(即订阅)所有输入供应。
  3. 当其中一个输入电源emit是一个值,emit交给我们的敲击者...
  4. ...但请确保我们遵循串行供应规则,即我们只emit一次一条消息;我们的两个输入电源可能会emit同时从不同线程获取值,因此这不是一个自动属性。
  5. 当我们所有的物资都已送出时done事件,发送done事件也。
  6. 如果我们点击的任何输入电源发送一个quit事件,中继它,并关闭所有其他输入电源的抽头。
  7. 确保我们没有任何奇怪的竞争会导致破坏供应语法emit* [done|quit].
  8. 当点击结果时Supply我们生产的产品已关闭,请务必关闭我们点击的所有(仍处于活动状态)输入电源上的点击。

祝你好运!

那么标准库是如何做到的呢?像这样:

method merge(*@s) {
    @s.unshift(self) if self.DEFINITE;  # add if instance method
    # [I elided optimizations for when there are 0 or 1 things to merge]
    supply {
        for @s {
            whenever $_ -> \value { emit(value) }
        }
    }
}

要点是supply块是大大缓解正确地实施reusable一项或多项操作Supply是。它旨在消除的主要风险是:

  • 在我们点击多个消息的情况下,无法正确处理同时到达的消息Supply,可能会导致我们进入腐败状态(因为我们可能希望编写的许多供给组合器也将具有状态;merge就这么简单,不用做)。 Asupplyblock 向我们承诺,我们一次只会处理一条消息,从而消除了这种危险。
  • 失去订阅跟踪,从而泄漏资源,这将成为任何长时间运行的程序中的一个问题。

第二个很容易被忽视,尤其是在使用像 Raku 这样的垃圾收集语言时。事实上,如果我开始迭代一些Seq然后在到达末尾之前停止这样做,迭代器将变得无法访问,并且 GC 会在一段时间后吃掉它。如果我正在迭代文件的行并且那里有一个隐式文件句柄,那么我将面临文件无法及时关闭的风险,并且如果我不幸的话,可能会用完句柄,但至少有some通往它的路径被关闭并释放资源。

反应式编程则不然:引用从生产者指向消费者,因此如果消费者“停止关心”但尚未关闭水龙头,那么生产者将保留其对消费者的引用(从而导致内存泄漏)并继续发送它发送消息(从而进行一次性工作)。这最终可能会导致应用程序崩溃。链接的 Cro 聊天示例就是一个示例:

my $chat = Supplier.new;

get -> 'chat' {
    web-socket -> $incoming {
        supply {
            whenever $incoming -> $message {
                $chat.emit(await $message.body-text);
            }
            whenever $chat -> $text {
                emit $text;
            }
        }
    }
}

当 WebSocket 客户端断开连接时会发生什么?水龙头上的Supply我们返回使用supply块被关闭,导致隐式close传入 WebSocket 消息的点击次数以及$chat。如果没有这个,订阅者列表$chat Supplier会无限制地增长,并反过来为每个先前的连接保持一定大小的对象图。

因此,即使在这种情况下,Supply是非常直接的参与,我们经常会随着时间的推移而订阅它。按需供应主要是资源的获取和释放;有时,该资源将是直播的订阅Supply.

一个公平的问题是,我们是否可以在没有supply堵塞。是的,我们可以;这可能有效:

my $chat = Supplier.new;

get -> 'chat' {
    web-socket -> $incoming {
        my $emit-and-discard = $incoming.map(-> $message {
                $chat.emit(await $message.body-text);
                Supply.from-list()
            }).flat;
        Supply.merge($chat, $emit-and-discard)
    }
}

注意到这是一些努力Supply-空间映射到无。我个人认为可读性较差 - 这甚至没有避免supply块,它只是隐藏在实现中merge。更棘手的是,所利用的供应数量随着时间的推移而变化,例如在递归文件观看中 https://github.com/raku-community-modules/IO-Notification-Recursive/blob/master/lib/IO/Notification/Recursive.pm其中可能会出现要观看的新目录。我真的不知道如何用标准库中出现的组合器来表达这一点。

我花了一些时间教授反应式编程(不是使用 Raku,而是使用 .Net)。对于一个异步流来说事情很容易,但是当我们开始处理具有多个异步流的情况时事情变得更加困难。有些东西自然适合组合符,例如“合并”或“zip”或“组合最新”。只要有足够的创造力,其他人就可以被打造成这样的形状——但对我来说,它常常感觉扭曲而不是富有表现力。当问题无法用组合器表达时会发生什么?用 Raku 术语来说,一个人创造输出Suppliers,利用输入电源,编写将输入内容发送到输出的逻辑,等等。每次都必须处理订阅管理、错误传播、完成传播和并发控制——而且很容易搞砸。

当然,存在supplyBlocks 也并没有停止在 Raku 中走上脆弱的道路。这就是我说的意思:

虽然经常会找到供应商,但很多时候最好编写一个发出值的供应块

我在这里没有考虑发布/订阅的情况,我们确实想要广播值并且处于反应链的入口点。我正在考虑我们点击一​​个或多个的情况Supply,采取价值观,做某事,然后emit事物变成另一种事物Supplier. 这是一个例子 https://github.com/shuppet/raku-api-discord/commit/ad31a677e99f936e3ac56a43744ffeb55bf062e6我将这样的代码迁移到supply block; 这是另一个例子 https://github.com/shuppet/raku-api-discord/commit/363102830ecef0fa93a82d2490277a9bd1375af1稍后在同一个代码库中出现。希望这些例子能澄清我的想法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解供应点块(按需供应) 的相关文章

  • sqlite只支持1笔交易?

    在使用 ADO NET 时 也许我错了 我不知道它叫什么 我注意到我只能通过连接开始事务 并且命令似乎有 command Transaction 获取事务数据但不启动事务本身 实际上 在查看时我在 System Data SQLite 中看
  • 数据流并发的一个很好的激励示例是什么?

    我了解数据流编程的基础知识 并且在Clojure API http richhickey github com clojure contrib dataflow api html 乔纳斯 博纳的演讲 http www slideshare
  • Erlang 如何并发处理访问邮箱

    关于如何使用erlang邮箱的信息有很多 但很少找到一篇论文或文档描述erlang如何在VM内部同时实际访问邮箱 据我了解 Erlang VM 必须执行锁定或 CAS 操作以确保消息完整性 erlang幕后有没有什么精巧的方法 我假设您所说
  • 并发.futures问题:为什么只有1个worker?

    我正在尝试使用concurrent futures ProcessPoolExecutor并行化串行任务 串行任务涉及从数字范围中查找给定数字的出现次数 我的代码如下所示 在执行过程中 我从任务管理器 系统监视器 顶部注意到 尽管给定了 m
  • 并发 log4j

    我有自己的日志引擎 它将日志写入带有阻塞队列的单独线程上 为了使用 标准软件 我正在考虑切换到 log4j 我不希望我的高并发软件因日志命令而变慢 这些日志命令在调用命令时将所有内容写入磁盘 log4j 可以用作垃圾箱吗 Log4j 是大多
  • 串流期货列表的最有效方式

    我通过流式传输对象列表来调用异步客户端方法 该方法返回 Future 迭代调用后返回的 Future 列表的最佳方法是什么 以便处理先出现的 Future 注意 异步客户端仅返回 Future 而不返回 CompletableFuture
  • 完全替换 ASP.Net 的会话

    ASP Net 会话对于传统的 WebForms 应用程序来说似乎很完美 但它们所做的一些事情对于现代 AJAX 和 MVC 应用程序来说是一个严重的问题 具体来说 访问 ASP Net 提供程序只有 3 种方法 锁定读和写 默认 会话被锁
  • 使用 Golang 通道处理 HTTP 请求

    我正在尝试构建一个简单的 Golang Appengine 应用程序 它使用通道来处理每个 http 请求 原因是我希望每个请求执行合理的大型内存计算 并且每个请求都以线程安全的方式执行 即来自并发请求的计算不会混合 这一点很重要 本质上
  • 如何从命令行提供非 slurpy 数组或命名数组?

    首先 raku perl6 非常棒 克罗也是如此 只花了一个周末就坠入爱河 然而现在我偶然发现了一些非常简单的事情 如果我在多重调度 MAIN 中使用 slurpy 参数 则会被识别并完美运行 multi MAIN config add h
  • 验证随时间变化的连续条件

    我想开发一个Python程序 从某个时刻开始 等待60秒再执行操作 该程序必须具有的另一个功能是 如果我更新初始时间 它必须开始检查条件 我想过用线程来做 但我不知道如何停止线程并以新的开始时间重新启动它 import thread imp
  • 非法监控状态异常

    如何将轮询线程传递给另一个线程进行处理 程序执行在控制器类中 该类具有 main 方法和线程池 主类控制器 public static void main String args throws InterruptedException Ru
  • Intel 64 和 IA-32 上的 MESI 有何意义

    MESI 的要点是保留共享内存系统的概念 然而 对于存储缓冲区 事情就变得复杂了 一旦数据到达 MESI 实现的缓存 下游内存就会保持一致 然而 在此之前 每个核心可能对内存位置 X 中的内容存在分歧 具体取决于每个核心的本地存储缓冲区中的
  • 没有公平性的DelayQueue有问题吗?

    在 Java 7 中 DelayQueue 的实现使用没有公平策略的 ReentrantLock 从长远来看 这是一个问题吗 线程会因此而饿死吗 Thanks 如果您考虑ScheduledThreadPoolExecutor 或任何其他生产
  • 并发:C++11 内存模型中的原子性和易失性

    全局变量在 2 个不同内核上的 2 个并发运行的线程之间共享 线程对变量进行写入和读取 对于原子变量 一个线程可以读取过时的值吗 每个核心可能在其缓存中具有共享变量的值 并且当一个线程写入缓存中的其副本时 不同核心上的另一个线程可能会从其自
  • 为什么在 10 个 Java 线程中递增一个数字不会得到 10 的值?

    我不明白 a 的值为0 为什么 a 不是10 那段代码的运行过程是怎样的 是否需要从Java内存模型来分析 这是我的测试代码 package com study concurrent demo import lombok extern sl
  • Guzzle 中的“并发”到底是什么?

    我没有找到太多关于concurrency选项中Pool 如果这是可以在服务器上打开的 TCP 套接字数量 那么问题是 我可以使用多少并发来更快地处理请求 我有这个使用的例子Pool I am using Laravel this is ba
  • 打印到 stdout 会导致阻塞的 goroutine 运行吗?

    作为一个愚蠢的基本线程练习 我一直在尝试实现理发师睡觉的问题 http en wikipedia org wiki Sleeping barber problem在戈兰 对于通道来说 这应该很容易 但我遇到了一个 heisenbug 也就是
  • 使用十进制数有理数是否会影响 Perl 6 的性能

    据我了解 Perl 6 尽可能将小数实现为有理数 以避免大多数其他语言中存在的浮点问题 有人做过基准测试或了解这样做的性能损失吗 使用十进制数有理数是否会影响 Perl 6 的性能 我认为最有用的总体答案是 不 不是真的 但让我详细说明一下
  • Condition 接口中的 signalAll 与对象中的 notificationAll

    1 昨天我才问过这个问题条件与等待通知机制 https stackoverflow com questions 10395571 condition vs wait notify mechanism 2 我想编辑相同的内容并在我的问题中添加
  • 使用GCD实现并发读独占写模型

    我试图了解使用 Grand Central Dispatch GCD 实现控制资源访问的并发读独占写模型的正确方法 假设有一个 NSMutableDictionary 被大量读取并且偶尔更新 确保读取始终与字典状态一致的正确方法是什么 当然

随机推荐