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
相关产品推荐
相关产品推荐

