- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
修订摘要
好吧,看起来系统调用肯定与 GC 有关,而根本问题只是 GC 发生得太频繁了。这似乎与 splitWhen 和 pack 的使用有关,我可以通过分析来判断。
splitWhen's implementation将每个 block 从惰性文本转换为严格文本,并将它们全部连接起来,因为它建立了一个 block 缓冲区。这势必会分配很多。
pack,因为它正在从一种类型转换为另一种类型,所以必须分配,这在我的内部循环中,所以这也是有道理的。
原始问题
我在基于 haskell 枚举器的 IO 中偶然发现了一些令人惊讶的系统调用事件。希望有人能对此有所了解。
我一直在玩弄我曾经写了几个月的快速 perl 脚本的 haskell 版本,时断时续。该脚本从每一行读取一些 json,然后打印出一个特定字段(如果存在)。
这是 perl 版本,以及我如何运行它。
cat ~/sample_input | perl -lpe '($_) = grep(/type/, split(/,/))' > /dev/null
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Enumerator as E
import qualified Data.Enumerator.Internal as EI
import qualified Data.Enumerator.Text as ET
import qualified Data.Enumerator.List as EL
import qualified Data.Text as T
import qualified Data.Text.IO as TI
import Data.Functor
import Control.Monad
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TLI
import System.Environment
import System.IO (stdin, stdout)
import GHC.IO.Handle (hSetBuffering, BufferMode(BlockBuffering))
fieldEnumerator field = enumStdin E.$= splitOn [',','\n'] E.$= grabField field
enumStdin = ET.enumHandle stdin
splitOn :: [Char] -> EI.Enumeratee T.Text T.Text IO b
splitOn chars = (ET.splitWhen (`elem` chars))
grabField :: String -> EI.Enumeratee T.Text T.Text IO b
grabField = EL.filter . T.isInfixOf . T.pack
intercalateNewlines = EL.mapM_ (\field -> (TI.putStrLn field >> (putStr "\n\n")))
runE enum = E.run_ $ enum E.$$ intercalateNewlines
main = do
(field:_) <- getArgs
runE $ fieldEnumerator field
55333/0x8816f5: 366125 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 366136 3 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 367209 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 367218 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 368449 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 368458 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 369525 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 369534 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 370610 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 370620 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 371735 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 371744 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 371798 5 2 select(0x1, 0x7FFF5FBFBA70, 0x7FFF5FBFB9F0, 0x0, 0x7FFF5FBFBAF0) = 1 0
55333/0x8816f5: 371802 3 1 read(0x0, SOME_JSON, 0x1FA0) = 8096 0
55333/0x8816f5: 372907 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 372918 3 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 374063 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 374072 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 375147 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 375156 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 376283 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 376292 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 376809 6 2 select(0x1, 0x7FFF5FBFBA70, 0x7FFF5FBFB9F0, 0x0, 0x7FFF5FBFBAF0) = 1 0
55333/0x8816f5: 376814 5 3 read(0x0, SOME_JSON, 0x1FA0) = 8096 0
55333/0x8816f5: 377378 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 377387 3 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 378537 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 378546 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 379598 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 379604 3 0 sigreturn(0x7FFF5FBFF9A0, 0x1E, 0x1) = 0 Err#-2
55333/0x8816f5: 379613 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 380667 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 380678 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 381862 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 381871 3 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 382032 6 2 select(0x1, 0x7FFF5FBFBA70, 0x7FFF5FBFB9F0, 0x0, 0x7FFF5FBFBAF0) = 1 0
55333/0x8816f5: 382036 4 2 read(0x0, SOME_JSON, 0x1FA0) = 8096 0
55333/0x8816f5: 383064 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 383073 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 384118 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 384127 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 385206 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 385215 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 386348 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 386358 3 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 387468 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 387477 11 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 387614 6 2 select(0x1, 0x7FFF5FBFBA70, 0x7FFF5FBFB9F0, 0x0, 0x7FFF5FBFBAF0) = 1 0
55333/0x8816f5: 387620 5 3 read(0x0, SOME_JSON, 0x1FA0) = 8096 0
55333/0x8816f5: 388597 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 388606 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 389707 3 0 sigprocmask(0x1, 0x10069BFA8, 0x10069BFAC) = 0x0 0
55333/0x8816f5: 389716 2 0 sigprocmask(0x3, 0x10069BFAC, 0x0) = 0x0 0
55333/0x8816f5: 390261 7 3 select(0x2, 0x7FFF5FBFBA70, 0x7FFF5FBFB9F0, 0x0, 0x7FFF5FBFBAF0) = 1 0
55333/0x8816f5: 390273 6 3 write(0x1, SOME_OUTPUT, 0x1FA0) = 8096 0
最佳答案
您是否担心分配或(开销来自?)对 sigprocmask 的调用?
如果是前者并且您想使用 enumerator
打包这个小改动有助于将 4k 测试集减少约 50%:8MB 的分配减少到 4MB,gen0 GC 从 15 减少到 6。
splitOn :: EI.Enumeratee T.Text T.Text IO b
splitOn = EL.concatMap (T.split fastSplit)
fastSplit :: Char -> Bool
fastSplit ',' = True
fastSplit '\n' = True
fastSplit _ = False
+RTS -sstderr -RTS
的统计数据):
8,212,680 bytes allocated in the heap 696,184 bytes copied during GC 148,656 bytes maximum residency (1 sample(s)) 30,664 bytes maximum slop 2 MB total memory in use (0 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 15 colls, 0 par 0.00s 0.00s 0.0001s 0.0005s Gen 1 1 colls, 0 par 0.00s 0.00s 0.0010s 0.0010s
After:
3,838,048 bytes allocated in the heap 689,592 bytes copied during GC 148,368 bytes maximum residency (1 sample(s)) 27,040 bytes maximum slop 2 MB total memory in use (0 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 6 colls, 0 par 0.00s 0.00s 0.0001s 0.0003s Gen 1 1 colls, 0 par 0.00s 0.00s 0.0006s 0.0006s
Which is a pretty reasonable improvement but definitely leaves something to be desired. Rather than kicking enumerator around too much more I took a stab at rewriting it in conduit-0.4.1 just for kicks. It should be equivalent...
import Data.Conduit as C
import qualified Data.Conduit.Binary as Cb
import qualified Data.Conduit.List as Cl
import qualified Data.Conduit.Text as Ct
import qualified Data.Text as T
import qualified Data.Text.IO as TI
import Control.Monad.Trans (MonadIO, liftIO)
import System.Environment
import System.IO (stdin)
grabField :: Monad m => String -> Conduit T.Text m T.Text
grabField = Cl.filter . T.isInfixOf . T.pack
printField :: MonadIO m => T.Text -> m ()
printField field = liftIO $ do
TI.putStrLn field
putStr "\n\n"
fastSplit :: Char -> Bool
fastSplit ',' = True
fastSplit '\n' = True
fastSplit _ = False
main :: IO ()
main = do
field:_ <- getArgs
runResourceT $ Cb.sourceHandle stdin
$$ Ct.decode Ct.utf8
=$ Cl.concatMap (T.split fastSplit)
=$ grabField field
=$ Cl.mapM_ printField
关于performance - 为什么基于 Haskell 枚举器的 IO 如此频繁地调用 sigprocmask?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10273696/
我正在阅读有关 Linux x86-64 系统的信号/ECF 的教科书章节(CS:APP,第 3 版,第 8 章,第 781 页),并遇到了这个: The sigsuspend function te
我有使用 sigprocmask fn 的多线程代码。据我了解,在多线程程序中未指定此调用的使用,我将删除此调用。但是,我面临的问题是,如果调用此函数,我的主线程将被卡住。我想了解为什么会发生这种情况
我的 C Unix 代码有问题。我将复制关键部分:因此,在第一个 sigprocmask 之后,我发送了一个信号,在 SIG_UNBLOCK 之后,前一个句柄(gestisciSignalDopoRe
下面的代码来自 Unix 环境中的高级编程,W. Richard Stevens 关于这本密码书说; "If the signal is sent to the process while it is
我目前正在研究使用 sigprocmask 在关键代码段时阻止某些信号(在本例中为 SIGALRM 和 SIGCHLD)正在执行。与这些信号关联的两个信号处理程序都将访问和修改一个中央数据结构,因此在
在多线程应用程序中使用 sigprocmask() 时,是否有任何众所周知的原因导致段错误? 我有一个使用 clone() 创建多个线程的应用程序。我已经确定,出于某种原因,当我使用 sigprocm
我想在汇编中使用 sigprocmask 来阻止函数中的所有信号。 以下代码在 C 中有效: #include #include int main() { sigset_t n={(uns
我有一个奇怪的行为,联机帮助页和谷歌没有帮助。 在我的代码中,我想在发送 SIGUSR2 时阻止/取消阻止 SIGINT。为此,我安装了信号处理程序并在函数中准备了掩码集: void installS
来自man sigprocmask: "If oset is not null, it is set to the previous value of the signal mask." 我的问题:无
我写了一小段代码。此代码首先阻止 {SIGSEGV},然后将 SIGRTMIN 添加到同一组。所以,我的最终信号集是 {SIGSEGV,SIGRTMIN}。因此,如果我使用 SIG_UNBLOCK,根
在第 10 章 APUE 信号中。 我对 sigprocmask()、SIG_BLOCK 和 SIG_SETMASK 有一些疑问。 书上说“我们在屏蔽信号时保存了旧面具”。我的理解是: 我们声明一个s
我还没有完全理解,如何使用sigprocmask()。特别是 set 和 oldset 及其语法如何工作以及如何使用它们。 int sigprocmask(int how, const sigset_
修订摘要 好吧,看起来系统调用肯定与 GC 有关,而根本问题只是 GC 发生得太频繁了。这似乎与 splitWhen 和 pack 的使用有关,我可以通过分析来判断。 splitWhen's impl
结构 sigaction: struct sigaction { void (*sa_handler)(int); /* addr of signal handler, *
我是一名优秀的程序员,十分优秀!