You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell async并发执行纯代码异常及与Control.Parallel的区别

Haskell并发并行问题解析

代码问题原因与修复

你的代码里,pure $ myFibonaci 45只是把纯计算包装成IO动作,但Haskell的惰性求值特性导致这个计算并没有在concurrently启动的线程中执行——直到print a时才会触发求值,此时整个计算都在主线程完成,自然看不到并行效果。

修复方案

需要强迫计算在concurrently的线程中执行,有两种常用方式:

方式1:使用evaluate强制求值

module Main where

import Control.Concurrent.Async (concurrently)
import Control.Exception (evaluate)

main :: IO ()
main = do
  putStrLn "Hello, Haskell!"
  (a, b) <- concurrently (evaluate $ myFibonaci 45) (evaluate $ myFibonaci 42)
  print a
  putStrLn "----"
  print b

myFibonaci :: Integer -> Integer
myFibonaci 0 = 0
myFibonaci 1 = 1
myFibonaci n = myFibonaci (n - 1) + myFibonaci (n - 2)

方式2:使用$!严格求值

concurrently (return $! myFibonaci 45) (return $! myFibonaci 42)

修改后,两个斐波那契计算会在独立线程中并行执行。

async 与 Control.Parallel 的区别

  • async:专注于IO动作的并发,属于显式线程调度。API(如concurrently、async)用于启动独立的IO线程,处理带副作用的操作(如IO读写、网络请求),或者需要在独立线程中执行的任务。每个调用都会创建受运行时调度的OS线程,IO动作启动后会立即执行。
  • Control.Parallel:专注于纯计算的并行,属于隐式火花调度。核心函数par、pseq用于给运行时提示:某个纯表达式可并行计算。运行时会将这些表达式转化为"火花"(轻量级计算单元),仅当有空闲CPU核心时才调度执行,完全在纯函数范畴内工作,适合分治类纯算法的并行优化。

Go无此类区分的原因

Go是严格求值语言,变量赋值、函数调用时会立即计算表达式,不存在惰性求值的延迟问题。同时,Go的goroutine是统一的并发原语:不管是纯计算还是IO操作,只要放入goroutine,调度器就会直接启动执行,无需额外区分纯并行和IO并发。此外,Go的GMP调度器会自动适配CPU密集型与IO密集型任务,开发者用goroutine和channel就能统一处理所有并发场景。

内容的提问来源于stack exchange,提问作者Emulebest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 02:16:31