《Haskell并行与并发编程》——第2章,第2.4节Deepseq

简介:

本节书摘来自异步社区《Haskell并行与并发编程》一书中的第2章,第2.4节Deepseq,作者【英】Simon Marlow,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 Deepseq
Haskell并行与并发编程
前面已经用过了force函数,其具体类型如下:
`
force :: NFData a => a -> a`
函数force会对其参数完全求值,然后返回。不过该函数并非内建,而是针对每种数据类型,通过NFData类对该函数的行为进行定义。NFData的意思是范式数据(normal-form data),其中范式是指不包含未被求值子表达式的值,“数据”则表示范式中不包含函数,因为无法看到函数里面的内容并对里面的内容求值1。

类NFData仅包含一个方法:
`
class NFData a where
rnf :: a -> ()
rnf a = a seq ()`
函数rnf名字的意思是“约化为范式”(reduce to normal-form)。该函数对其参数完全求值,然后返回()。默认通过seq来实现,对于没有子结构的类型来说很方便,只需使用默认定义即可。例如:Bool的实例可以简单地定义:

instance NFData Bool
模块Control.Deepseq对库中所有其他的常见类型均提供了实例。

对于自定义的类型,可能需要实现相应的NFData的实例。例如,对于二叉树类型:
`
data Tree a = Empty | Branch (Tree a) a (Tree a)`
那么,其NFData的实例如下:

instance NFData a => NFData (Tree a) where
  rnf Empty = ()
  rnf (Branch l a r) = rnf l `seq` rnf a `seq` rnf r

实现的思路为递归地对数据类型的组成部分应用rnf,然后将这些rnf的调用通过seq组合起来。

Control.DeepSeq模块中还有一些其他运算,例如:

deepseq :: NFData a => a -> b -> b
deepseq a b = rnf a `seq` b

函数deepseq因其和seq的相似性而得名:和seq类似,都是强制求值。如果把弱首范式看成是浅(shallow)求值,那么范式就是深(deep)求值,因此得名deepseq。

函数force是通过deepseq定义的:

force :: NFData a => a -> a
force x = x `deepseq` x

函数force的功能应该被认为是将WHNF转换为NF(normal form),也就是,当程序将force x求值成WHNF时,x会被求值成NF。

图像说明文字将表达式求值为范式需要对整个数据结构进行遍历,因此需要铭记,对于大小为n的数据结构,其复杂度是O(n),而对seq来说,只有O(1)。因此,应该避免对同一数据反复使用force或deepseq函数。

WHNF和NF就像天平的两端,但是,根据数据类型的不同,还有许多处于中间的“不同程度的求值”。例如:前面的length函数对列表的脊(spine)求值,即展开了列表,但未对列表的元素求值。parallel包中的模块Control.Seq提供了一系列组合子,通过组合,可以对数据结构达到不同程度的求值。本书虽然不会在例子中使用这些运算,但对读者也许会有所帮助。

1不过,纯粹为了方便,定义了一个函数的NFData实例,会将函数求值为WHNF(弱首范式),因为经常会有数据结构里面包含函数,而尽管如此,还是想尽可能地对这样的数据结构进行求值。

相关文章
|
23天前
|
算法 数据处理 Python
Python并发编程:解密异步IO与多线程
本文将深入探讨Python中的并发编程技术,重点介绍异步IO和多线程两种常见的并发模型。通过对比它们的特点、适用场景和实现方式,帮助读者更好地理解并发编程的核心概念,并掌握在不同场景下选择合适的并发模型的方法。
|
1月前
|
安全 Python
Python中的并发编程:多线程与多进程技术探究
本文将深入探讨Python中的并发编程技术,重点介绍多线程和多进程两种并发处理方式的原理、应用场景及优缺点,并结合实例分析如何在Python中实现并发编程,以提高程序的性能和效率。
|
22天前
|
数据采集 数据库 C++
python并发编程:并发编程中是选择多线程呢?还是多进程呢?还是多协程呢?
python并发编程:并发编程中是选择多线程呢?还是多进程呢?还是多协程呢?
20 0
|
1月前
|
API 开发者 Python
深入浅出Python协程:提升并发编程效率
在当今高速发展的互联网时代,高并发成为了软件开发中的一个重要需求。本文将引领读者深入理解Python中的协程(Coroutine)概念,探讨其在并发编程中的应用及优势。我们将从协程的基础概念出发,通过实例讲解如何使用asyncio库来编写高效的异步代码。文章旨在帮助读者掌握协程的工作原理和使用方法,从而在实际开发中能够更好地利用Python进行高效的并发编程。
|
1月前
|
缓存 资源调度 Go
内存模型与调度器在Go语言并发编程中的应用与优化
【2月更文挑战第16天】Go语言以其独特的并发编程模型而备受瞩目,其中内存模型和调度器是支撑其高效并发执行的关键机制。本文将探讨内存模型与调度器在Go语言并发编程中的应用场景,并介绍一些优化策略,帮助开发者更好地利用这些机制,提升程序的性能和稳定性。
|
2月前
|
并行计算 开发者 Python
Python中的并发编程:异步IO与多线程比较
本文将探讨Python中的并发编程方法,着重比较异步IO和多线程两种不同的实现方式。通过对它们的特点、优缺点以及适用场景进行分析,帮助读者更好地理解并发编程在Python中的应用。
26 1
|
2月前
|
数据采集 调度 开发者
深入理解Python协程:提升并发编程效率
本文旨在深入探讨Python协程的工作原理及其在并发编程中的应用。不同于传统的摘要,我们将以一种创新的方式——通过一个实际案例——来展示协程如何解决并发问题,同时提升代码的运行效率和可读性。我们将从协程的基本概念出发,逐步深入到事件循环、任务调度等核心机制。通过本文,读者将能够掌握使用Python协程处理高并发任务的技巧,以及如何有效地利用现代Python框架来构建高效、可维护的异步应用程序。
|
2月前
|
Python
深入浅出Python协程:提升并发性能的艺术
本文旨在深入探讨Python协程的内部机制及其在提升程序并发性能中的关键作用。不同于传统的摘要,我们将通过一个简洁明了的比喻来揭示协程的本质:想象一个高效的快餐厨房,厨师(主线程)在准备一个订单(任务)时,如果需要等待某个步骤(如烤面包),他会转而开始准备下一个订单,而不是站在那里等待。这样,厨房的整体效率得到了极大提升。Python协程正是这样一种机制,它允许代码在等待操作(如I/O操作)完成时“挂起”,转而执行其他任务,从而显著提高并发性能。本文将通过示例和解析,带你一步步深入理解协程的工作原理,以及如何在你的Python项目中有效地利用协程来提升性能。
39 1
|
2月前
|
开发者 Python
深入浅出Python协程:提高并发性能的秘诀
在现代软件开发中,提高应用程序的并发处理能力是一项挑战,尤其是在资源受限的情况下。本文将探讨Python协程的概念、原理及其在提高并发性能中的应用。通过对比传统多线程和多进程模型,我们将揭示Python协程如何以更少的资源消耗实现高效的并发任务处理。文章还将通过实例代码演示协程的创建、事件循环的管理以及异步编程的最佳实践,旨在为读者提供一种更轻量级、更高效的并发编程方法。
|
2月前
|
开发者 Python
深入浅出Python协程:提高并发性能的利器
本文旨在深入探讨Python中的协程机制,一种轻量级的并发编程解决方案。与传统的多线程和多进程相比,协程提供了更高效的并发性能,尤其是在I/O密集型应用中。我们将从协程的基本概念入手,解析其工作原理,并通过实例讲解如何在Python中使用协程来优化程序性能。文章还将对比协程与其他并发模型的优缺点,帮助读者全面理解协程在现代软件开发中的应用价值。
27 3