Haskell Thrift库在性能测试中比C ++慢300倍 [英] Haskell Thrift library 300x slower than C++ in performance test

查看:455
本文介绍了Haskell Thrift库在性能测试中比C ++慢300倍的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个应用程序,其中包含两个组件 - 服务器写在Haskell,和客户端写在Qt(C + +)。我使用thrift来沟通他们,我不知道为什么它工作这么慢。



我做了一个性能测试,这里是我的机器上的结果



结果



  C ++服务器和C ++客户端: 

发送100个ping - 13.37 ms
传输1000000大小的向量 - 433.58 ms
收到:3906.25 kB
从服务器传输100000个项目 - 1090.19 ms
传输100000个项目到服务器 - 631.98 ms

Haskell服务器和C ++客户端:

发送100个ping 3959.97 ms
传输1000000大小的向量 - 12481.40 ms
Recieved :3906.25 kB
从服务器传输100000个项目 - 26066.80 ms
将100000个项目传输到服务器 - 1805.44 ms

为什么Haskell在这个测试中这么慢?



这里是文件:



文件



performance.thrift



 命名空间hs test 
命名空间cpp test

struct Item {
1:可选字符串名称
2:可选列表< i32>坐标
}

struct ItemPack {
1:可选列表< Item>项目
2:可选映射< i32,项目> mappers
}


服务ItemStore {
void ping()
ItemPack getItems(1:字符串名称,2:i32计数)
bool setItems(1:ItemPack items)

list< i32> getVector(1:i32 count)
}



Main.hs



  { - #LANGUAGE ScopedTypeVariables# - } 
模块主要其中

导入数据.Int
import Data.Maybe(fromJust)
导入合格的Data.Vector为Vector
导入合格的Data.HashMap.Strict为HashMap
import网络

- Thrift库
import Thrift.Server

- 生成的Thrift模块
import Performance_Types
import ItemStore_Iface
import ItemStore


i32toi :: Int32 - > Int
i32toi = fromIntegral

itoi32 :: Int - > Int32
itoi32 = fromIntegral

port :: PortNumber
port = 9090

data ItemHandler = ItemHandler

实例ItemStore_Iface ItemHandler
ping _ = return()--putStrLnping
getItems _ mtname mtsize = do
let size = i32toi $ fromJust mtsize
item i = Item mtname Vector.fromList $ map itoi32 [i..100])
items = map item [0 ..(size-1)]
itemsv = Vector.fromList items
mappers = zip itoi32 [0 ..(size-1)])items
mappersh = HashMap.fromList mappers
itemPack = ItemPack(Just itemsv)(Just mappersh)
putStrLngetItems
return itemPack

setItems _ _ = do putStrLnsetItems
return True

getVector _ mtsize = do putStrLngetVector
let size = i32toi $ fromJust mtsize
return $ Vector.generate size itoi32

main :: IO()
main = do
_< - runBasicServer ItemHandler process port
putStrLn服务器已停止



ItemStore_client.cpp



  #include< iostream> 
#include< chrono>
#includegen-cpp / ItemStore.h

#include< transport / TSocket.h>
#include< transport / TBufferTransports.h>
#include< protocol / TBinaryProtocol.h>

使用命名空间apache :: thrift;
使用命名空间apache :: thrift :: protocol;
使用命名空间apache :: thrift :: transport;

使用命名空间测试;
using namespace std;

#define TIME_INIT std :: chrono :: _ V2 :: steady_clock :: time_point start,stop; \
std :: chrono :: duration< long long int,std :: ratio< 1ll,100000000011> >持续时间;
#define TIME_START start = std :: chrono :: steady_clock :: now();
#define TIME_END duration = std :: chrono :: steady_clock :: now() - start; \
std :: cout<< chrono :: duration< double,std :: milli> (duration).count()< ms< std :: endl;

int main(int argc,char ** argv){

boost :: shared_ptr< TSocket> socket(new TSocket(localhost,9090));
boost :: shared_ptr< TTransport> transport(new TBufferedTransport(socket));
boost :: shared_ptr< TProtocol>协议(新TBinaryProtocol(传输));

ItemStoreClient服务器(协议);
transport-> open();

TIME_INIT

long pings = 100;
cout<< 发送<< pings<< pings< endl;
TIME_START
for(auto i = 0; i< pings; ++ i)
server.ping();
TIME_END


long vectorSize = 1000000;

cout<< 转移<< vectorSize< 尺寸向量<< endl;
std :: vector< int> v;
TIME_START
server.getVector(v,vectorSize);
TIME_END
cout<< Recieved:<< v.size()* sizeof(int)/ 1024.0 < kB< endl;


long itemsSize = 100000;

cout<< 转移<< itemsSize<< 来自服务器的项目< endl;
ItemPack items;
TIME_START
server.getItems(items,test,itemsSize);
TIME_END


cout<< 转移<< itemsSize<< items to server< endl;
TIME_START
server.setItems(items);
TIME_END

transport-> close();

return 0;
}



ItemStore_server.cpp



< pre class =lang-cpp prettyprint-override> #includegen-cpp / ItemStore.h
#include< thrift / protocol / TBinaryProtocol.h>
#include< thrift / server / TSimpleServer.h>
#include< thrift / transport / TServerSocket.h>
#include< thrift / transport / TBufferTransports.h>

#include< map>
#include< vector>

using namespace :: apache :: thrift;
using namespace :: apache :: thrift :: protocol;
using namespace :: apache :: thrift :: transport;
using namespace :: apache :: thrift :: server;


使用命名空间测试;
using boost :: shared_ptr;

class ItemStoreHandler:virtual public ItemStoreIf {
public:
ItemStoreHandler(){
}

void ping(){
// printf(ping\\\
);
}

void getItems(ItemPack& _return,const std :: string& name,const int32_t count){

std :: vector< Item>项目;
std :: map< int,Item>映射器

for(auto i = 0; i std :: vector< int>坐标;
for(auto c = i; c <100; ++ c)
coordinates.push_back(c);

项目项;
item .__ set_name(name);
item .__ set_coordinates(coordinates);

items.push_back(item);
mappers [i] = item;
}

_return .__ set_items(items);
_return .__ set_mappers(mappers);
printf(getItems\\\
);
}

bool setItems(const ItemPack& items){
printf(setItems\\\
);
return true;
}

void getVector(std :: vector< int32_t>& _return,const int32_t count){
for(auto i = 0; i _return.push_back(i);
printf(getVector\\\
);
}
};

int main(int argc,char ** argv){
int port = 9090;
shared_ptr< ItemStoreHandler> handler(new ItemStoreHandler());
shared_ptr< TProcessor>处理器(new ItemStoreProcessor(handler));
shared_ptr< TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr< TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr< TProtocolFactory> protocolFactory(new TBinaryProtocolFactory())

TSimpleServer服务器(处理器,serverTransport,transportFactory,protocolFactory);
server.serve();
return 0;
}



Makefile



  GEN_SRC:= gen-cpp / ItemStore.cpp gen-cpp / performance_constants.cpp gen-cpp / performance_types.cpp 
GEN_OBJ:= $(patsubst %.cpp,%。o,$(GEN_SRC))

THRIFT_DIR:= / usr / local / include / thrift
BOOST_DIR:= / usr / local / include
b $ b INC:= -I $(THRIFT_DIR)-I $(BOOST_DIR)

.PHONY:all clean

all:ItemStore_server ItemStore_client

%.o:%.cpp
$(CXX)--std = c ++ 11 -Wall -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H $(INC)-c $& -o $ @

ItemStore_server:ItemStore_server.o $(GEN_OBJ)
$(CXX)$ ^ -o $ @ -L / usr / local / lib -lthrift -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H

ItemStore_client:ItemStore_client.o $(GEN_OBJ)
$(CXX)$ ^ -o $ @ -L / usr / local / lib -lthrift -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H

clean:
$(RM)* .o ItemStore_server ItemStore_client



编译并运行



我使用thrift 0.9生成文件(此处):

  $ thrift --gen cpp performance.thrift 
$ thrift --gen hs performance.thrift

编译

  $ make 
$ ghc Main.hs gen-hs / ItemStore_Client.hs gen-hs / ItemStore.hs gen-hs / ItemStore_Iface.hs gen-hs / Performance_Consts.hs gen-hs / Performance_Types.hs -Wall -O2

运行Haskell测试:

  $ ./Main& 
$ ./ItemStore_client

运行C ++ test:

  $ ./ItemStore_server& 
$ ./ItemStore_client

记住在每次测试后杀死服务器



更新



编辑 getVector 方法使用向量.generate 而不是 Vector.fromList ,但仍然没有效果



/ h1>

由于@MdxBhmt的建议,我测试了 getItems 函数,如下所示:

  getItems _ mtname mtsize = do let size = i32toi $! from just mtsize 
item i = Item mtname(Just $!Vector.enumFromN(i :: Int32)(100-(fromIntegral i)))
itemsv = Vector.map item $ Vector.enumFromN 0 -1)
itemPack = ItemPack(Just itemsv)Nothing
putStrLngetItems
return itemPack

这是严格的,并且改进了矢量生成vs基于我原来的实现的替代方法:

  getItems _ mtname mtsize = do let size = i32toi $ fromJust mtsize 
item i = Item mtname(Just $ Vector.fromList $ map itoi32 [i..100])
items = map item [0 .. size-1)]
itemsv = Vector.fromList items
itemPack = ItemPack(Just itemsv)Nothing
putStrLngetItems
return itemPack

请注意,没有发送HashMap。第一个版本给出时间12338.2毫秒,第二个是11698.7毫秒,没有加速:(



更新3



我向 Thrift Jira 报告了一个问题



更新4由abhinav



这是完全不科学,但使用GHC 7.8.3与Thrift 0.9.2和@ MdxBhmt的版本 getItems ,则差异显着降低。

  C ++服务器和C ++客户端:

发送100 pings:8.56 ms
传输1000000大小向量:137.97 ms
收到:3906.25 kB
从服务器传输100000个项目:467.78 ms
将100000个项目传输到服务器:207.59 ms

Haskell服务器和C ++客户端:

发送100个ping:24.95 ms
收到:3906.25 kB
传送1000000大小的向量:378.60 ms
传送100000来自服务器的项目:233.74 ms
将100000个项目传输到服务器:913.07 ms

执行,每次重新启动服务器。结果是可重现的。



请注意,原始问题的源代码(使用@ MdxBhmt的 getItems 实现)不按原样编译。必须进行以下更改:

  getItems _ mtname mtsize = do let size = i32toi $! from just mtsize 
item i = Item mtname(Just $!Vector.enumFromN(i :: Int32)(100-(fromIntegral i)))
itemsv = Vector.map item $ Vector.enumFromN 0 -1)
itemPack = ItemPack(Just itemsv)Nothing
putStrLngetItems
return itemPack

getVector _ mtsize = do putStrLngetVector
let size = i32toi $ fromJust mtsize
return $ Vector.generate size itoi32


解决方案

每个人都指出,罪魁祸首是thrift库,但我会专注于您的代码(我可以帮助获得一些速度)



使用您的代码的简化版本,计算 itemsv

  testfunc mtsize = itemsv 
where size = i32toi $ fromJust mtsize
item i = Item(Just $ Vector.fromList $ map itoi32 [i..100])
items = map item [0 ..(size-1)]
itemsv = Vector.fromList items

,您在 item i 中创建了许多中间数据。由于懒惰,那些小而快的计算向量会导致数据的延迟,当我们可以立即使用它们。



有两个仔细放置 $!,代表严格的评估:

  item i = Item(Just $!Vector.fromList $!map itoi32 [i..100])

运行时会减少25%对于大小1e5和1e6)。



但是这里有一个更有问题的模式:你生成一个列表,将其转换为向量,而不是直接构建向量。



查看最后两行,你创建一个列表 - >将一个函数 - >转换成一个向量。



好吧,向量和list非常相似,你可以做类似的事情!
所以你必须生成一个向量 - > vector.map并完成。不再需要将列表转换为向量,并且向量上的映射通常比列表快!



所以你可以摆脱并重写以下 itemsv

  itemsv = Vector.map item $ Vector.enumFromN 0(size-1)

重新应用逻辑到 item i ,我们删除所有列表。

  testfunc3 mtsize = itemsv 
其中
size = i32toi $!从$ JUST mtsize
item i = Item(Just $!Vector.enumFromN(i :: Int32)(100-(fromIntegral i)))
itemsv = Vector.map item $ Vector.enumFromN 0(size- 1)

比初始运行时减少50%。


I'm building an application which contains two components - server written in Haskell, and client written in Qt (C++). I'm using thrift to communicate them, and I wonder why is it working so slow.

I made a performance test and here is the result on my machine

Results

C++ server and C++ client:

Sending 100 pings                    -    13.37 ms
Transfering 1000000 size vector      -   433.58 ms
Recieved: 3906.25 kB
Transfering 100000 items from server -  1090.19 ms
Transfering 100000 items to server   -   631.98 ms

Haskell server and C++ client:

Sending 100 pings                       3959.97 ms
Transfering 1000000 size vector      - 12481.40 ms
Recieved: 3906.25 kB
Transfering 100000 items from server - 26066.80 ms
Transfering 100000 items to server   -  1805.44 ms

Why is Haskell so slow in this test? How can I improve it performance?

Here are the files:

Files

performance.thrift

namespace hs test
namespace cpp test

struct Item {
    1: optional string    name
    2: optional list<i32> coordinates
}

struct ItemPack {
    1: optional list<Item>     items
    2: optional map<i32, Item> mappers
}


service ItemStore {
    void ping()
    ItemPack getItems(1:string name, 2: i32 count) 
    bool     setItems(1: ItemPack items)

    list<i32> getVector(1: i32 count)
}

Main.hs

{-# LANGUAGE ScopedTypeVariables #-}   
module Main where

import           Data.Int  
import           Data.Maybe (fromJust) 
import qualified Data.Vector as Vector
import qualified Data.HashMap.Strict  as HashMap
import           Network

-- Thrift libraries
import           Thrift.Server

-- Generated Thrift modules
import Performance_Types
import ItemStore_Iface
import ItemStore


i32toi :: Int32 -> Int
i32toi = fromIntegral

itoi32 :: Int -> Int32
itoi32 = fromIntegral

port :: PortNumber
port = 9090

data ItemHandler = ItemHandler

instance ItemStore_Iface ItemHandler where
    ping _                   = return () --putStrLn "ping"
    getItems _ mtname mtsize = do 
        let size = i32toi $ fromJust mtsize
            item i = Item mtname (Just $ Vector.fromList $ map itoi32 [i..100])
            items = map item [0..(size-1)]
            itemsv = Vector.fromList items 
            mappers = zip (map itoi32 [0..(size-1)]) items 
            mappersh = HashMap.fromList mappers
            itemPack = ItemPack (Just itemsv) (Just mappersh)
        putStrLn "getItems"
        return itemPack

    setItems _ _             = do putStrLn "setItems"
                                  return True

    getVector _ mtsize       = do putStrLn "getVector"
                                  let size = i32toi $ fromJust mtsize
                                  return $ Vector.generate size itoi32

main :: IO ()
main = do
    _ <- runBasicServer ItemHandler process port 
    putStrLn "Server stopped"

ItemStore_client.cpp

#include <iostream>
#include <chrono>
#include "gen-cpp/ItemStore.h"

#include <transport/TSocket.h>
#include <transport/TBufferTransports.h>
#include <protocol/TBinaryProtocol.h>

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using namespace test;
using namespace std;

#define TIME_INIT  std::chrono::_V2::steady_clock::time_point start, stop; \
                   std::chrono::duration<long long int, std::ratio<1ll, 1000000000ll> > duration;
#define TIME_START start = std::chrono::steady_clock::now(); 
#define TIME_END   duration = std::chrono::steady_clock::now() - start; \
                   std::cout << chrono::duration <double, std::milli> (duration).count() << " ms" << std::endl;

int main(int argc, char **argv) {

    boost::shared_ptr<TSocket> socket(new TSocket("localhost", 9090));
    boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));

    ItemStoreClient server(protocol);
    transport->open();

    TIME_INIT

    long pings = 100;
    cout << "Sending " << pings << " pings" << endl;
    TIME_START
    for(auto i = 0 ; i< pings ; ++i)
        server.ping();
    TIME_END


    long vectorSize = 1000000;

    cout << "Transfering " << vectorSize << " size vector" << endl;
    std::vector<int> v;
    TIME_START
    server.getVector(v, vectorSize);
    TIME_END
    cout << "Recieved: " << v.size()*sizeof(int) / 1024.0 << " kB" << endl;


    long itemsSize = 100000;

    cout << "Transfering " << itemsSize << " items from server" << endl;
    ItemPack items;
    TIME_START
    server.getItems(items, "test", itemsSize);
    TIME_END


    cout << "Transfering " << itemsSize << " items to server" << endl;
    TIME_START
    server.setItems(items);
    TIME_END

    transport->close();

    return 0;
}

ItemStore_server.cpp

#include "gen-cpp/ItemStore.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>

#include <map>
#include <vector>

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;


using namespace test;
using boost::shared_ptr;

class ItemStoreHandler : virtual public ItemStoreIf {
  public:
    ItemStoreHandler() {
    }

    void ping() {
        // printf("ping\n");
    }

    void getItems(ItemPack& _return, const std::string& name, const int32_t count) {

        std::vector <Item> items;
        std::map<int, Item> mappers;

        for(auto i = 0 ; i < count ; ++i){
            std::vector<int> coordinates;
            for(auto c = i ; c< 100 ; ++c)
                coordinates.push_back(c);

            Item item;
            item.__set_name(name);
            item.__set_coordinates(coordinates);

            items.push_back(item);
            mappers[i] = item;
        }

        _return.__set_items(items);
        _return.__set_mappers(mappers);
        printf("getItems\n");
    }

    bool setItems(const ItemPack& items) {
        printf("setItems\n");
        return true;
    }

    void getVector(std::vector<int32_t> & _return, const int32_t count) {
        for(auto i = 0 ; i < count ; ++i)
            _return.push_back(i);
        printf("getVector\n");
    }
};

int main(int argc, char **argv) {
    int port = 9090;
    shared_ptr<ItemStoreHandler> handler(new ItemStoreHandler());
    shared_ptr<TProcessor> processor(new ItemStoreProcessor(handler));
    shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

    TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
    server.serve();
    return 0;
}

Makefile

GEN_SRC := gen-cpp/ItemStore.cpp gen-cpp/performance_constants.cpp gen-cpp/performance_types.cpp
GEN_OBJ := $(patsubst %.cpp,%.o, $(GEN_SRC))

THRIFT_DIR := /usr/local/include/thrift
BOOST_DIR := /usr/local/include

INC := -I$(THRIFT_DIR) -I$(BOOST_DIR)

.PHONY: all clean

all:   ItemStore_server ItemStore_client

%.o: %.cpp
    $(CXX) --std=c++11 -Wall -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H $(INC) -c $< -o $@

ItemStore_server: ItemStore_server.o $(GEN_OBJ) 
    $(CXX) $^ -o $@ -L/usr/local/lib -lthrift -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H

ItemStore_client: ItemStore_client.o $(GEN_OBJ)
    $(CXX) $^ -o $@ -L/usr/local/lib -lthrift -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H

clean:
    $(RM) *.o ItemStore_server ItemStore_client

Compile and run

I generate files (using thrift 0.9 available here) with:

$ thrift --gen cpp performance.thrift
$ thrift --gen hs performance.thrift

Compile with

$ make
$ ghc Main.hs gen-hs/ItemStore_Client.hs gen-hs/ItemStore.hs gen-hs/ItemStore_Iface.hs gen-hs/Performance_Consts.hs gen-hs/Performance_Types.hs -Wall -O2

Run Haskell test:

$ ./Main& 
$ ./ItemStore_client

Run C++ test:

$ ./ItemStore_server&
$ ./ItemStore_client

Remember to kill server after each test

Update

Edited getVector method to use Vector.generate instead of Vector.fromList, but still no effect

Update 2

Due to suggestion of @MdxBhmt I tested the getItems function as follows:

getItems _ mtname mtsize = do let size = i32toi $! fromJust mtsize
                                  item i = Item mtname (Just $!  Vector.enumFromN (i::Int32) (100- (fromIntegral i)))
                                  itemsv = Vector.map item  $ Vector.enumFromN 0  (size-1)
                                  itemPack = ItemPack (Just itemsv) Nothing 
                              putStrLn "getItems"
                              return itemPack

which is strict and has improved Vector generation vs its alternative based on my original implementation:

getItems _ mtname mtsize = do let size = i32toi $ fromJust mtsize
                                  item i = Item mtname (Just $ Vector.fromList $ map itoi32 [i..100])
                                  items = map item [0..(size-1)]
                                  itemsv = Vector.fromList items 
                                  itemPack = ItemPack (Just itemsv) Nothing
                              putStrLn "getItems"
                              return itemPack

Notice that there is no HashMap sent. The first version gives time 12338.2 ms and the second is 11698.7 ms, no speedup :(

Update 3

I reported an issue to Thrift Jira

Update 4 by abhinav

This is completely unscientific but using GHC 7.8.3 with Thrift 0.9.2 and @MdxBhmt's version of getItems, the discrepancy is significantly reduced.

C++ server and C++ client:

Sending 100 pings:                     8.56 ms
Transferring 1000000 size vector:      137.97 ms
Recieved:                              3906.25 kB
Transferring 100000 items from server: 467.78 ms
Transferring 100000 items to server:   207.59 ms

Haskell server and C++ client:

Sending 100 pings:                     24.95 ms
Recieved:                              3906.25 kB
Transferring 1000000 size vector:      378.60 ms
Transferring 100000 items from server: 233.74 ms
Transferring 100000 items to server:   913.07 ms

Multiple executions were performed, restarting the server each time. The results are reproducible.

Note that the source code from the original question (with @MdxBhmt's getItems implementation) will not compile as-is. The following changes will have to be made:

getItems _ mtname mtsize = do let size = i32toi $! fromJust mtsize
                                  item i = Item mtname (Just $!  Vector.enumFromN (i::Int32) (100- (fromIntegral i)))
                                  itemsv = Vector.map item  $ Vector.enumFromN 0  (size-1)
                                  itemPack = ItemPack (Just itemsv) Nothing 
                              putStrLn "getItems"
                              return itemPack

getVector _ mtsize       = do putStrLn "getVector"
                              let size = i32toi $ fromJust mtsize
                              return $ Vector.generate size itoi32

解决方案

Everyone is pointing out that is the culprit is the thrift library, but I'll focus on your code (and where I can help getting some speed)

Using a simplified version of your code, where you calculate itemsv:

testfunc mtsize =  itemsv
  where size = i32toi $ fromJust mtsize
        item i = Item (Just $ Vector.fromList $ map itoi32 [i..100])
        items = map item [0..(size-1)]
        itemsv = Vector.fromList items 

First, you have many intermediate data being created in item i. Due to lazyness, those small and fast to calculate vectors becomes delayed thunks of data, when we could had them right away.

Having 2 carefully placed $!, that represent strict evaluation :

 item i = Item (Just $! Vector.fromList $! map itoi32 [i..100])

Will give you a 25% decrease in runtime (for size 1e5 and 1e6).

But there is a more problematic pattern here: you generate a list to convert it as a vector, in place of building the vector directly.

Look those 2 last lines, you create a list -> map a function -> transform into a vector.

Well, vectors are very similar to list, you can do something similar! So you'll have to generate a vector -> vector.map over it and done. No more need to convert a list into a vector, and maping on vector is usually faster than a list!

So you can get rid of items and re-write the following itemsv:

  itemsv = Vector.map item  $ Vector.enumFromN 0  (size-1)

Reapplying the same logic to item i, we eliminate all lists.

testfunc3 mtsize = itemsv
   where 
      size = i32toi $! fromJust mtsize
      item i = Item (Just $!  Vector.enumFromN (i::Int32) (100- (fromIntegral i)))
      itemsv = Vector.map item  $ Vector.enumFromN 0  (size-1)

This has a 50% decrease over the initial runtime.

这篇关于Haskell Thrift库在性能测试中比C ++慢300倍的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆