与curl相比,为什么我在Haskell中的https getter这么慢?

Mus*_*han 10 curl haskell

我正在Haskell中编写一个简单的https getter代码.收到响应后,我将其保存到压缩文件中.然而,与curl和gzip组合相比,我的版本非常慢.如何使卷曲更快?详情如下.

Haskell代码(fetcher.hs):

import Control.Lens
import qualified Codec.Compression.GZip as GZip
import qualified Data.ByteString.Lazy as BL
import Network.Wreq

writeURIBodyToFile :: FilePath -> String -> IO()
writeURIBodyToFile filePath uri = do
  response <- get uri
  let body = (response ^. responseBody)
  BL.writeFile filePath (GZip.compress body)

main :: IO ()
main = writeURIBodyToFile "out.html.gz" "https://www.sahibinden.com/ilan/vasita-otomobil-seat-hatasiz-boyasiz-tramersiz-dsg-leon-469484363/detay/"
Run Code Online (Sandbox Code Playgroud)

Haskell结果:

$ ghc -o fetcher fetcher.hs
$ time ./fetcher 

real    0m9.240s
user    0m8.840s
sys     0m0.232s
Run Code Online (Sandbox Code Playgroud)

卷曲结果:

$ time curl "https://www.sahibinden.com/ilan/vasita-otomobil-seat-hatasiz-boyasiz-tramersiz-dsg-leon-469484363/detay/" | gzip > out.html.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  102k  100  102k    0     0   331k      0 --:--:-- --:--:-- --:--:--  332k

real    0m0.524s
user    0m0.156s
sys     0m0.040s
Run Code Online (Sandbox Code Playgroud)

编辑:我也尝试过使用http-conduit包,没有任何改变.

import qualified Data.ByteString.Lazy as BL
import           Network.HTTP.Simple

main :: IO ()
main = do
    response <- httpLBS "https://www.sahibinden.com/ilan/vasita-otomobil-seat-hatasiz-boyasiz-tramersiz-dsg-leon-469484363/detay/"
    BL.writeFile "outnew.html" $ getResponseBody response
Run Code Online (Sandbox Code Playgroud)

Edit2:我还检查了与tcpdump的连接,没有连接问题.

EDIT3: GHCi, version 7.10.3

Edit4:编译命令 ghc -o fetcher fetcher.hs

编辑5:2019年2月使用此代码无法重现该问题:

{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import qualified Data.ByteString.Char8 as B8

main :: IO ()
main = httpBS "https://www.sahibinden.com/ilan/vasita-otomobil-mercedes-benz-mercedes-benz-c-180-fascination-7g-tronic-ozel-renk-652750468/detay" >>= B8.putStrLn . getResponseBody
Run Code Online (Sandbox Code Playgroud)

结果:

$ ghc -o fetcher fetcher.hs
$ time ./fetcher 
real    0m0,549s
user    0m0,093s
sys     0m0,021s
Run Code Online (Sandbox Code Playgroud)

编辑6:再次,问题无法在2019年2月的第一个代码示例上重现 GHCi, version 8.0.2

han*_*rik 3

我最好的猜测是,您的 HTTP 客户端不会考虑Content-Lengthhttp 标头,而只是继续下载,直到远程服务器关闭连接,即

a:可能比仅仅读取标头慢得多Content-Length许多网络服务器保持套接字打开的时间比需要的时间长得多(通常用于套接字重用方案)

b:天真/简单的 http 客户端的共同主题。

你可以用一个小的 netcat http 服务器来确认这一点,如下所示:

printf "HTTP/1.0 200 OK\r\nContent-Length: 3\r\n\r\nabcx" | nc -l 9999
Run Code Online (Sandbox Code Playgroud)

现在点击http://127.0.0.1:9999并检查响应,优化为考虑Content-Length标头的 http 客户端会说响应正文是abc,而未优化考虑Content-Length标头的 http 客户端会说响应正文是abcx

在此输入图像描述

注意:此命令应该适用于类 UNIX 系统(Linux、*BSD、MacOS),但可能不适用于 Windows 系统。如果你运行的是 Windows,它可以在Cygwin上运行(并且可能在 WSL 上运行,但我还没有尝试过,我仍在滚动不支持 WSL 的 Windows 7)