猫效应和异步 IO 细节

2024-01-17

这几天我一直在思考猫效应和 IO。我觉得我对这种效果有一些误解,或者只是我错过了它的要点。

  1. 首先——如果IO可以取代Scala的Future,我们如何创建异步IO任务?使用IO.shift? Using IO.async? Is IO.delay同步还是异步?我们可以用这样的代码创建一个通用的异步任务吗Async[F].delay(...)?或者当我们调用 IO 时会发生异步unsafeToAsync or unsafeToFuture?
  2. 猫效应中的异步和并发有什么意义?他们为什么分开?
  3. IO是绿线程吗?如果是的话,为什么猫效应中有一个 Fiber 对象?据我了解,Fiber 是绿色线程,但文档声称我们可以将 IO 视为绿色线程。

我希望对这些问题进行一些澄清,因为我无法理解这些猫效应文档,而互联网也没有那么有帮助......


如果IO可以取代Scala的Future,我们如何创建异步IO任务

首先,我们需要澄清什么是“异步任务。通常async意味着“不阻塞操作系统线程”,但既然你提到Future,有点模糊。比如说,如果我写:

Future { (1 to 1000000).foreach(println) }

它不会是async,因为它是一个阻塞循环和阻塞输出,但它可能会在不同的操作系统线程上执行,由隐式 ExecutionContext 管理。等效的猫效果代码是:

for {
  _ <- IO.shift
  _ <- IO.delay { (1 to 1000000).foreach(println) }
} yield ()

(这不是较短的版本)

So,

  • IO.shift用于更改线程/线程池。Future每次操作都会执行此操作,但它在性能方面并不是免费的。
  • IO.delay{ ... }(又名IO { ... }) does NOT使任何事情异步并执行NOT切换线程。它用于创建简单的IO来自同步副作用 API 的值

现在,让我们回到真正的异步。这里要理解的是:

     每个异步计算都可以表示为一个接受回调的函数。

是否使用返回的APIFuture或Java的CompletableFuture,或者像NIO这样的东西CompletionHandler,这一切都可以转换为回调。这是什么IO.async用于:您可以转换任何函数接受回调 to an IO。如果是这样的话:

for {
  _ <- IO.async { ... }
  _ <- IO(println("Done"))
} yield ()

Done仅当(并且如果)计算时才会打印...回电。您可以将其视为阻塞绿色线程,但不阻塞操作系统线程。

So,

  • IO.async用于转换任何已经异步了计算为IO.
  • IO.delay用于转换任何完全同步计算为IO.
  • 具有真正异步计算的代码的行为就像阻塞绿色线程一样。

工作时最接近的类比Futures 正在创建一个scala.concurrent.Promise并返回p.future.


或者当我们使用 unsafeToAsync 或 unsafeToFuture 调用 IO 时会发生异步?

有点。和IO, nothing除非您调用其中之一(或使用IOApp)。但是 IO 并不保证您会在不同的操作系统线程上执行,甚至异步执行,除非您明确要求这样做IO.shift or IO.async.

您可以保证线程随时切换,例如(IO.shift *> myIO).unsafeRunAsyncAndForget()。这是可能的,正是因为myIO除非有要求,否则不会被执行,无论您是否将其作为val myIO or def myIO.

但是,您无法神奇地将阻塞操作转换为非阻塞操作。这也是不可能的Future也不与IO.


猫效应中的异步和并发有什么意义?他们为什么分开?

Async and Concurrent (and Sync) 是类型类。它们的设计是为了让程序员可以避免被锁定cats.effect.IO并且可以为您提供支持您选择的任何 API,例如 monix Task 或 Scalaz 8 ZIO,甚至 monad 转换器类型,例如OptionT[Task, *something*]。 fs2、monix 和 http4s 等库都利用它们,让您有更多选择来使用它们。

Concurrent在上面添加额外的东西Async,其中最重要的是.cancelable and .start。这些与Future,因为这根本不支持取消。

.cancelable是一个版本.async这还允许您指定一些逻辑来取消您正在包装的操作。一个常见的例子是网络请求 - 如果您对结果不再感兴趣,您可以中止它们而无需等待服务器响应,并且不会在读取响应上浪费任何套接字或处理时间。你可能永远不会直接使用它,但它有它的用处。

但是,如果您无法取消可取消的操作,那么它们有什么用呢?这里的关键观察是您无法从操作本身取消操作。其他人必须做出这个决定,这就会发生同时与操作本身(这是类型类的名称的来源)。那就是那里.start进来。简而言之,

      .start是绿色线程的显式分叉。

Doing someIO.start类似于做val t = new Thread(someRunnable); t.start(),除了现在是绿色的。和Fiber本质上是一个精简版本ThreadAPI:你可以做.join,就像Thread#join(),但它不会阻塞操作系统线程;和.cancel,这是安全版本.interrupt().


请注意,还有其他方法可以分叉绿色线程。例如,进行并行操作:

val ids: List[Int] = List.range(1, 1000)
def processId(id: Int): IO[Unit] = ???
val processAll: IO[Unit] = ids.parTraverse_(processId)

会将所有 ID 的处理分叉到绿色线程,然后将它们全部连接起来。或者使用.race:

val fetchFromS3: IO[String] = ???
val fetchFromOtherNode: IO[String] = ???

val fetchWhateverIsFaster = IO.race(fetchFromS3, fetchFromOtherNode).map(_.merge)

将并行执行提取,为您提供第一个完成的结果,并自动取消较慢的提取。所以,做.start并使用Fiber不是分叉更多绿色线程的唯一方法,只是最明确的方法。答案是:

IO是绿线程吗?如果是的话,为什么猫效应中有一个 Fiber 对象?据我了解,Fiber 是绿色线程,但文档声称我们可以将 IO 视为绿色线程。

  • IO就像一个绿色线程,这意味着您可以让许多线程并行运行,而无需操作系统线程的开销,并且 for-compression 中的代码的行为就好像它在计算结果时阻塞一样。

  • Fiber是一个用于控制显式分叉(等待完成或取消)的绿色线程的工具。

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

猫效应和异步 IO 细节 的相关文章

  • “函数是第一等值”这到底是什么意思?

    有人可以用一些很好的例子清楚地解释它吗 在解释函数式编程时 我在 Scala 中遇到了这句话 一流 并不是一个正式定义的概念 但它通常意味着一个实体具有三个属性 有可能used 不受限制 只要 普通 值可以 即从函数传递和返回 放入容器等
  • 覆盖 Predef 的隐式转换

    我有多个返回 java lang Integer 的方法 然后使用 Scala 的 Predef 隐式转换将其隐式转换为 Int 下面是它的编写方式there https github com scala scala blob v2 11
  • 用惯用的 Scala 更新大型数据结构

    我已经尝试 Scala 一段时间了 并且经常遇到支持不可变数据结构的建议 但是当你有一个像这样的数据结构时3D 场景图 大型神经网络或任何具有大量需要频繁更新的对象的东西 对场景中的对象进行动画处理 训练神经网络 这似乎是 运行时效率极低
  • ';'预期但发现“导入” - Scala 和 Spark

    我正在尝试使用 Spark 和 Scala 来编译一个独立的应用程序 我不知道为什么会收到此错误 topicModel scala 2 expected but import found error import org apache sp
  • Spark:出现心跳错误后丢失数据

    我有一个在 Spark 集群上运行的 Python 程序 有四个工作线程 它处理一个包含大约 1500 万条记录的巨大 Oracle 表 检查结果后发现大约有600万条记录没有插入 我的写入功能如下 df write format jdbc
  • Scala 中抛出异常,什么是“官方规则”

    我正在 Coursera 上学习 Scala 课程 我也开始阅读 Odersky 的 Scala 书 我经常听到的是 在函数式语言中抛出异常不是一个好主意 因为它破坏了控制流 并且我们通常返回一个失败或成功的 Either Scala 2
  • Haskell scala 互操作性

    我是 Scala 初学者 来自面向对象范式 在了解 Scala 的函数式编程部分时 我被引导到 Haskell 纯函数式编程语言 探索 SO 问题答案 我发现 Java Haskell 具有互操作性 我很想知道 Scala Haskell
  • Scala(或 Java)中泛型函数的特化

    是否可以在 Scala 中专门化泛型函数 或类 例如 我想编写一个将数据写入 ByteBuffer 的通用函数 def writeData T buffer ByteBuffer data T buffer put data 但由于 put
  • Scala 2.9 无法在 Windows XP 上运行“hello world”示例

    我正在尝试在 Windows XP 上使用 scala 2 9 1 Final 运行 HelloWorld 示例 object HelloWorld extends App println Hello World 文件另存为Hello sc
  • Akka Stream Graph 恢复问题

    我创建了一个图表来并行化具有相同输入的两个流 这些流产生 Future Option Entity 如果 flowA 失败 我想返回 Future None 但恢复似乎没有被调用 val graph Flow Input Future Op
  • Scala 宏的位置怎么了?

    我试图获取宏参数的原始输入字符串 但返回的位置似乎有点偏离 考虑这个宏 例如 object M import scala reflect macros Context import language experimental macros
  • Scala 的代码覆盖率工具 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 具有上限的联合类型

    我正在遵循这个问题的公认答案中提出的技术如何定义 类型析取 联合类型 https stackoverflow com questions 3508077 does scala have type disjunction union type
  • Spark:如何使用crossJoin

    我有两个数据框 df1有 100000 行并且df2有 10000 行 我想创建一个df3这是两者的交叉连接 val df3 df1 crossJoin df2 这将产生 10 亿行 尝试在本地运行它 但似乎需要很长时间 您认为本地可以实现
  • andThen 类型不匹配的 Scala 链接函数

    我有一堆函数可以清理文本并将它们分成单词 最小的例子 val txt Mary had a little nlamb val stopwords Seq a def clean text String String text replace
  • Java 8 Stream,获取头部和尾部

    Java 8 引入了Stream http download java net jdk8 docs api java util stream Stream html类似于 Scala 的类Stream http www scala lang
  • Scala Spark 包含与不包含

    我可以使用 contains 过滤 RDD 中的元组 如下所示 但是使用 不包含 来过滤 RDD 又如何呢 val rdd2 rdd1 filter x gt x 1 contains 我找不到这个的语法 假设这是可能的并且我没有使用Dat
  • 获取SettingKey[T]的值

    我正在开发一个用于文档生成的插件 我想将所有生成的文件输出到我选择的目录中 该目录可以是SBT的子目录target目录 如下 val newTargetDirectory SettingKey File document target di
  • 为什么这些类型参数不符合类型细化?

    为什么此 Scala 代码无法进行类型检查 trait T type A trait GenFoo A0 S lt T type A A0 trait Foo S lt T extends GenFoo S A S 我不明白为什么 类型参数
  • Akka-Http 2.4.9 抛出 java.lang.NoClassDefFoundError: akka/actor/ActorRefFactory 异常

    我正在尝试使用 Akka http 构建一个简单的 Web 服务 我遵循了这个指南 http doc akka io docs akka 2 4 9 scala http low level server side api html htt

随机推荐

  • 清除任务中的所有活动?

    我有一个启动屏幕活动 然后是一个登录活动 我的历史堆栈如下所示 SplashActivity LoginActivity 当用户通过 LoginActivity 成功登录时 我想启动 WelcomeActivity 但清除整个堆栈 Spla
  • 如何避免页面对象中的复合类名称错误?

    当我尝试使用有空格的类名时class country name 在页面对象中 我得到 Compound class names not permitted Selenium WebDriver Error UnknownError 如何使用
  • React Router 传递参数。如何?

    具有以下 React Router const AppRoutes
  • Autofac 已下载,我可以访问构建器方法,但不能访问 RegisterControllers 方法

    下面的代码是我到目前为止所拥有的 RegisterControllers 方法不存在 尽管我可以在 autofac 文档以及其他堆栈溢出问题上看到它 Visual Studio 一直说 ContainerBuilder 不包含 Regist
  • 使用 TypeFamilies 派生实例

    我有一个类型类Foo具有关联类型 LANGUAGE TypeFamilies class Foo a where type Bar a foo a gt Bar a 现在我想定义一个包含关联类型之一的数据类型 并派生一个Show它的实例 d
  • HTML与大虾

    我尝试使用 prawn 生成日志条目的 PDF 然后条目存储在 bbcode b bold b 等 中并转换为 html 显示 大虾有什么办法可以显示html吗 这听起来像虾格式 http github com sandal prawn f
  • WordPress 页面重定向到主页

    我有一个 WordPress 网站http www wjewel com http www wjewel com 网站的所有页面都被重定向到主页 没有用于重定向的 htaccess 文件或 web config 文件 有人可以指导我这个问题
  • 如何重复更新android TextView来模拟动画

    我希望一旦按下菜单中的按钮 TextView 中的文本就会不断变化 这是我的菜单的 onOptionsItemSelected public boolean onOptionsItemSelected MenuItem item switc
  • pip3安装pyautogui,错误代码1

    我无法安装 pyautogui 我已经尝试了一切 例如 pip3 install pillow 也按照网站上的步骤操作pyautogui 网站 http pyautogui readthedocs io en latest install
  • 配置 Redis 以与 AppHarbor 良好配合

    我使用 AppHarbor 作为 CI 环境来验证我的提交 我在 AppHarbor 中收到错误 因为 Redis 无法写入磁盘 Error RedisResponseException MISCONF Redis is configure
  • Adobe AIR 键盘挂钩

    我正在尝试向我的 AIR 应用程序添加一项功能 即使应用程序最小化 该功能也可以侦听 可配置的 全局键盘事件 例如 CTRL ALT SHIFT F12 抓取屏幕截图 我找不到任何方法来注册键盘挂钩 并且监听键盘事件仅在应用程序具有焦点时捕
  • 如何防止 iframe 页面被插入 IE 浏览历史记录中

    我在将 iframe 页面插入 IE9 的浏览历史记录时遇到很多麻烦 这很痛苦 因为您必须多次单击后退才能到达上一页 这是什么原因呢 是浏览器的bug还是页面的bug 编辑 我意识到我正在使用 javascript 来更新页面上所有 ifr
  • C++ Map 使用非默认构造函数初始化对象

    在 C 中 假设我有一个无序映射定义如下 unordered map
  • Process.Start() 明显慢于在控制台中执行

    我使用以下命令执行 exe 时遇到性能问题Process Start NET 的执行时间大约是控制台的 5 倍 什么会导致这种情况 这是一个测试程序 public static void Main string argv for int i
  • 如何将事件对象传递给命名函数

    我有一个用于单击事件的事件处理程序 事件处理程序是一个命名函数而不是匿名函数 如何将事件对象传递给这个命名函数 usual example sel click function ev do stuff which involves the
  • notifyDataSetChanged 不会刷新 RecyclerView

    我有一个奇怪的问题 我切换到RecyclerView from ListView我无法刷新或通知我的更改ListView 我尝试打电话Item this notifyDataSetChanged 以及其他刷新方法View但它不起作用 反而R
  • setImeOptions:为什么软键盘上不显示“完成”按钮?

    我尝试使用以下命令在软键盘上设置 完成 按钮input setImeOptions EditorInfo IME ACTION DONE 但 完成 按钮根本不显示在软键盘上 请问有什么建议吗 public void modif int po
  • 切换弹出窗口并在外部单击时切换它

    我有一个问题 我正在尝试制作一个弹出窗口切换toggleClass 不过 我还制定了一条从 StackOverflow 获得的规则 当在外部单击时 弹出窗口会消失 但是 当我单击登录按钮时 它会出现 但我无法再使用登录按钮使其消失 但我已经
  • 2D OpenGL 场景因大量重叠形状而变慢

    我正在使用 OpenGL 绘制 2D 形状 他们没有使用那么多多边形 我注意到我可以有很多很多的形状 只要它们不重叠 如果我在一个形状后面得到一个形状 等等 它真的开始滞后 我觉得我可能做错了什么 这是正常的吗 有没有办法解决这个问题 我不
  • 猫效应和异步 IO 细节

    这几天我一直在思考猫效应和 IO 我觉得我对这种效果有一些误解 或者只是我错过了它的要点 首先 如果IO可以取代Scala的Future 我们如何创建异步IO任务 使用IO shift Using IO async Is IO delay同