首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >较差的haskell网络性能

较差的haskell网络性能
EN

Stack Overflow用户
提问于 2010-11-19 19:00:33
回答 3查看 3K关注 0票数 13

我正在编写一些类似openvpn的程序,并认为这将是提高我的Haskell知识的好人选。然而,我遇到了相当严重的性能问题。

它所做的:它打开一个TUN设备;它将自己绑定在一个UDP端口上,启动2个线程(forkIO,但是由于fdRead而用-threaded编译)。我还没有使用金枪鱼包,我自己完全在Haskell完成。

线程1:从tun设备读取数据包(fdRead)。使用UDP套接字发送它。

线程2:从UDP套接字读取数据包(recv);将其发送到tun设备(fdWrite)。

问题1:在这个配置中,fdRead返回字符串,我使用了接受字符串的Network.Socket函数。我在本地系统(一些iptables魔术)上进行了配置,我可以在本地主机上运行15 on /s,程序基本上运行在100%的CPU上。太慢了。我能做些什么来提高成绩吗?

问题2:我将不得不在发送的数据包中添加一些内容;然而,sendMany网络函数只接受ByteString;从Fd读取返回字符串。转换很慢。转换为手柄似乎对TUN设备的效果不够好.

问题3:我想要将一些信息存储在Data.Heap (函数堆)中(我需要使用'takeMin‘,虽然对于3个条目来说,它太过了,但是做起来很容易:)。所以我创建了一个MVar,在每个接收到的数据包上,我从MVar中提取了堆,用新的信息更新了堆,并把它放回了MVar,现在它开始消耗大量的内存。可能是因为旧堆垃圾收集得不够快/不够频繁?

有没有办法解决这些问题,还是我必须回到C.?我所做的应该主要是零拷贝操作--我是否使用了错误的库来实现它?

==================

我所做的:-当放到MVar上时,我做了:

代码语言:javascript
复制
a `seq` putMVar mvar a

对记忆泄漏有很好的帮助。

  • 改为ByteString;现在我只使用“读/写”而没有进一步的处理,得到42 to /s。C版本的容量大约为56 so /s,因此这是可以接受的。
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-11-19 19:37:58

绳子很慢。真的,真的,非常慢。这是一个单独链接的反单元格列表,每个单元格包含一个unicode字符。将一个字符写入套接字需要将每个字符转换为字节,将这些字节复制到数组中,然后将该数组传递给系统调用。这其中哪一部分听起来像你想要做的?:)

您希望只使用ByteString。ByteString IO函数实际上在可能的情况下使用零拷贝IO。特别是查看关于黑客的网络字节串包。它包含所有经过优化以有效使用ByteString的网络库的版本。

票数 23
EN

Stack Overflow用户

发布于 2010-11-19 21:15:29

关于你的前两个问题,卡尔是对的。关于最后一个问题,请考虑使用严格的并发包

票数 6
EN

Stack Overflow用户

发布于 2010-11-20 04:49:52

下面是两个示例程序:客户机和服务器。使用GHC 7.0.1和Network2.3,我在我的新双核笔记本电脑上获得了超过7500 Mbps的回环(大约90%的CPU总使用量)。我不知道UDP引入了多少开销,但这是一个相当多的数字。

代码语言:javascript
复制
--------------------
-- Client program --
--------------------
module Main where

import qualified Data.ByteString as C
import Network.Socket hiding (recv)
import Network.Socket.ByteString (recv)

import System.IO
import Control.Monad

main :: IO ()
main = withSocketsDo $
    do devNull <- openFile "/dev/null" WriteMode
       addrinfos <- getAddrInfo Nothing (Just "localhost") (Just "3000")
       let serveraddr = head addrinfos
       sock <- socket (addrFamily serveraddr) Stream defaultProtocol
       connect sock (addrAddress serveraddr)
       forever $ do
         msg <- recv sock (256 * 1024) -- tuning recv size is important!
         C.hPutStr devNull msg
       sClose sock


--------------------
-- Server program --
--------------------
module Main where

-- import Control.Monad (unless)
import Network.Socket hiding (recv)
import qualified Data.ByteString.Lazy as S
import Network.Socket.ByteString.Lazy (
                                       --recv, 
                                       sendAll)

main :: IO ()
main = withSocketsDo $
       do addrinfos <- getAddrInfo
                        (Just (defaultHints {addrFlags = [AI_PASSIVE]}))
                        Nothing (Just "3000")
          let serveraddr = head addrinfos
          sock <- socket (addrFamily serveraddr) Stream defaultProtocol
          bindSocket sock (addrAddress serveraddr)
          listen sock 1
          (conn, _) <- accept sock
          talk conn
          sClose conn
          sClose sock

     where
       talk :: Socket -> IO ()
       talk conn = sendAll conn $ S.repeat 7
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4228416

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档