libcurl長連接高並發多線程


libcurl長連接高並發高性能

自己開發了一個股票智能分析軟件,功能很強大,需要的點擊下面的鏈接獲取:

https://www.cnblogs.com/bclshuai/p/11380657.html

掃碼關注公眾號

 

 

 

目錄

1      背景介紹

2      長短連接實測分析

2.1          長連接參數設置說明

2.2          長短連接區別

2.2.1     短連接

2.2.2     長連接

2.3          長短連接測試分析

2.3.1     短連接調用url1

2.3.2     長連接調用url1

2.3.3     長連接調用url2

2.3.4     長連接調用兩次不同的url

2.3.5     總結分析

2.3.6 源碼下載地址

 

 

1       背景介紹

項目中需要用到Curl頻繁調用的情況,發現curl接口調用速度緩慢。為了實現curl高性能,高並發,需要研究如何實現高性能高並發。研究方向有三個。

(1)   長連接。考慮采用長連接的方式去開發。首先研究下長連接和短連接的性能區別。curl內部是通過socket去連接通訊。socket每次連接最為耗時,如果能夠復用連接,長時間連接,減少每次socket連接的時間,則可以大大減少時間,提高效率。

(2)   多線程。單個線程下載速度畢竟有限,使用多線程去調用接口。實現高並發高性能,需要考慮資源分配和沖突的問題。

(3)   異步調用。和socket異步調用的原理類似。同步調用會阻塞等待,造成CPU占用率高,電腦卡死等問題。異步調用則是數據接收完成后才會取通知調用成功,處理數據。

 

 

2       長短連接實測分析

2.1  長連接參數設置說明

Curl提供了三個參數來設置

/* 設置TCP連接為長連接 */

curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

/* 設置長連接的休眠時間*/

curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

/* 設置心跳發送時間,心使得socket長時間保活,小於KEEPIDLE時間 */

curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 20L);

/* 設置連接的超時時間,大於心跳時間*/

curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);

2.2  長短連接區別

2.2.1         短連接

短連接一般分為4步驟:初始化、設置參數、執行請求、清理資源。即使用curl_easy_setopt設置該curl為長連接,因為最后被curl_easy_cleanup(curl),所以這個socket連接會被中斷銷毀,不會保持長連接。具體步驟如下:

(1)CURL* curl = curl_easy_init();//創建一個curl對象

(2)curl_easy_setopt(curl,……);//可以設置多個參數url,result

(3)res = curl_easy_perform(curl);//執行請求

(4)curl_easy_cleanup(curl);//清除curl

 

實例代碼如下:

int CHttpClient::Get(const std::string & strUrl, std::string & strResponse)

{

       int res;

       CURL* curl = curl_easy_init();

       if (NULL == curl)

       {

              return CURLE_FAILED_INIT;

       }

       if (m_bDebug)

       {

              curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

              curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);

       }

       curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());

       curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);

       curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);

       /* enable TCP keep-alive for this transfer */

       curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

       /* keep-alive idle time to 120 seconds */

       curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

       /* interval time between keep-alive probes: 60 seconds */

       curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 20L);

       curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);

       /**

       * 當多個線程都使用超時處理的時候,同時主線程中有sleep或是wait等操作。

       * 如果不設置這個選項,libcurl將會發信號打斷這個wait從而導致程序退出。

       */

       //curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);

       curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20);

       res = curl_easy_perform(curl);

       if (res != 0)

       {

              //FIRE_ERROR("  Get error %d", res);

       }

    //CurlMutiTreadMutex::GetInstance()->muti_curl_easy_cleanup(curl);

       curl_easy_cleanup(curl);

       return res;

}

2.2.2         長連接

長連接是我們創建了curl對象之后,不立刻使用curl_easy_cleanup清理掉,而是保存起來,下一個請求,只要重新設置url,執行請求,就可以復用以前的socket連接。

 

示例代碼如下

頭文件

CURL* GetCurl();

CURL* CreateCurl();

void PutCurl(CURL* curl);

QVector<CURL*> m_VectCurl;

QMutex m_mutex;

源文件

CURL* RestClientPool::GetCurl()

{

    CURL* curl = NULL;

    m_mutex.lock();

    if (m_VectCurl.size()>0)

    {

       

        curl = m_VectCurl.front();

        m_VectCurl.pop_front();

       

    }

    m_mutex.unlock();

    if(curl==NULL)

    {

        curl = CreateCurl();

    }

    return curl;

}

 

CURL* RestClientPool::CreateCurl()

{

    CURL* curl = curl_easy_init();

    if (NULL == curl)

    {

        return NULL;

    }

    if (m_bDebug)

    {

        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

        curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);

    }

    //curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);

    //curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);

    /* enable TCP keep-alive for this transfer */

    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* keep-alive idle time to 120 seconds */

    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 300L);

    /* interval time between keep-alive probes: 60 seconds */

    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 20L);

    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);

    /**

    * 當多個線程都使用超時處理的時候,同時主線程中有sleep或是wait等操作。

    * 如果不設置這個選項,libcurl將會發信號打斷這個wait從而導致程序退出。

    */

    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20);

    return curl;

}

 

void RestClientPool::PutCurl(CURL* curl)

{

   

    m_mutex.lock();

    m_VectCurl.push_back(curl);

    m_mutex.unlock();

}

int RestClientPool::Get(const std::string & strUrl, std::string & strResponse)

{

    int res;

    //CURL* curl = CurlMutiTreadMutex::GetInstance()->muti_curl_easy_init();

    CURL* curl = GetCurl();

    if (NULL == curl)

    {

        return CURLE_FAILED_INIT;

    }

   

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());

    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);

    res = curl_easy_perform(curl);

    if (res != 0)

    {

        printf("req error %d",res);

    }

    PutCurl(curl);

    return res;

}

2.3  長短連接測試分析

用上述的長連接和短連接進行測試,分四種情況進行測試分析。

(1)   shot連接循環調用1000次url1;

(2)   long連接循環調用1000次url1;

(3)   long連接循環調用1000次url2;

(4)   long連接循環調用1000次,每次循環中各調用一次url1和一次url2;

測試程序代碼

 

#include <QtCore/QCoreApplication>

#include"RestClientPool.h"

#include "RestClient.h"

#include <QDateTime>

#include <string>

using namespace std;

int main(int argc, char *argv[])

{

    QCoreApplication a(argc, argv);

    CHttpClient m_shotclient;

    RestClientPool m_longClient;

    QDateTime StartTime = QDateTime::currentDateTime();

    string strUrl = "http://qt.gtimg.cn/q=sz002415";

    string strUrl2= "http://hq.sinajs.cn/list=sz002415";

    string strResponse = "";

    for (int i=0;i<1000;i++)

    {

        m_longClient.Get(strUrl, strResponse);

        m_longClient.Get(strUrl, strResponse);

    }

    QDateTime timeEnd = QDateTime::currentDateTime();

    int time = timeEnd.toTime_t()- StartTime.toTime_t();

    printf("using time %d", time);

    return a.exec();

}

2.3.1         短連接調用url1

如下圖所示,短連接每次調用都會創建一個socket連接。

 

輸出

 

[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60102[WSPConnect] Socket ip 127.0.0.1:60104線程 0x89b4 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60107[WSPConnect] Socket ip 127.0.0.1:60109線程 0x8de8 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60112[WSPConnect] Socket ip 127.0.0.1:60114線程 0x7d20 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60118[WSPConnect] Socket ip 127.0.0.1:60120線程 0x7e1c 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60124[WSPConnect] Socket ip 127.0.0.1:60126線程 0xa328 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60129[WSPConnect] Socket ip 127.0.0.1:60132線程 0x9a68 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60137[WSPConnect] Socket ip 127.0.0.1:60140線程 0xbd80 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60151[WSPConnect] Socket ip 127.0.0.1:60153線程 0x7360 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60156[WSPConnect] Socket ip 127.0.0.1:60158線程 0xbfac 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60161[WSPConnect] Socket ip 127.0.0.1:60163線程 0xd18 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60166[WSPConnect] Socket ip 127.0.0.1:60168線程 0x8ca8 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60171[WSPConnect] Socket ip 127.0.0.1:60174線程 0xbc88 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60177[WSPConnect] Socket ip 127.0.0.1:60179線程 0x90b0 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60183[WSPConnect] Socket ip 127.0.0.1:60185線程 0x8c38 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60189[WSPConnect] Socket ip 127.0.0.1:60191線程 0xa8d0 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60194[WSPConnect] Socket ip 127.0.0.1:60196線程 0x76a0 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60200[WSPConnect] Socket ip 127.0.0.1:60202線程 0x7c6c 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60205[WSPConnect] Socket ip 127.0.0.1:60208線程 0x8618 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60211[WSPConnect] Socket ip 127.0.0.1:60213線程 0xa300 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60218[WSPConnect] Socket ip 127.0.0.1:60220線程 0xa3f8 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60223[WSPConnect] Socket ip 127.0.0.1:60225線程 0xb81c 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60228[WSPConnect] Socket ip 127.0.0.1:60230線程 0xa554 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 127.0.0.1:60233[WSPConnect] Socket ip 127.0.0.1:60235線程 0xa0f0 已退出,返回值為 0 (0x0)。

 

2.3.2         長連接調用url1

如下圖所示,長連接調用1000次url,只創建了一個socket連接。所用的時間也大幅減少,只有27秒的時間。

 

 輸出

 

WSPStartup ===> D:\Project\CurlHighSpeed\Win32\Release\CurlHighSpeed.exe使用鏈式SPI[WSPConnect] Socket ip 127.0.0.1:60584[WSPConnect] Socket ip 127.0.0.1:60586WSPStartup ===> D:\Project\CurlHighSpeed\Win32\Release\CurlHighSpeed.exe“CurlHighSpeed.exe”(Win32): 已加載“C:\Program Files (x86)\Sangfor\SSL\ClientComponent\2_SangforNsp.dll”。模塊已生成,不包含符號。
“CurlHighSpeed.exe”(Win32): 已卸載“C:\Program Files (x86)\Sangfor\SSL\ClientComponent\2_SangforNsp.dll”
“CurlHighSpeed.exe”(Win32): 已加載“C:\Program Files (x86)\Sangfor\SSL\ClientComponent\2_SangforNsp.dll”。模塊已生成,不包含符號。
“CurlHighSpeed.exe”(Win32): 已加載“C:\Windows\SysWOW64\dbghelp.dll”。“包括”/“排除”設置禁用了加載功能。
“CurlHighSpeed.exe”(Win32): 已加載“C:\Windows\SysWOW64\rasadhlp.dll”。“包括”/“排除”設置禁用了加載功能。
“CurlHighSpeed.exe”(Win32): 已加載“C:\Windows\SysWOW64\FWPUCLNT.DLL”。“包括”/“排除”設置禁用了加載功能。
“CurlHighSpeed.exe”(Win32): 已加載“C:\Windows\SysWOW64\bcrypt.dll”。“包括”/“排除”設置禁用了加載功能。
線程 0x9adc 已退出,返回值為 0 (0x0)。
[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80[WSPConnect] Socket ip 120.204.10.232:80“CurlHighSpeed.exe”(Win32): 已加載“C:\Windows\SysWOW64\uxtheme.dll”。“包括”/“排除”設置禁用了加載功能。

 

 

2.3.3         長連接調用url2

如下圖所示調用不同的url2,調用1000次,用時40秒。所用的時間和url1是不同的,這個和請求的服務器以及請求的數據不一致,所以會有不同的耗時。

 

 

 

WSPStartup ===> D:\Project\CurlHighSpeed\Win32\Release\CurlHighSpeed.exe使用鏈式SPI[WSPConnect] Socket ip 127.0.0.1:58122[WSPConnect] Socket ip 127.0.0.1:58126

WSPStartup ===> D:\Project\CurlHighSpeed\Win32\Release\CurlHighSpeed.exe“CurlHighSpeed.exe”(Win32): 已加載“C:\Program Files (x86)\Sangfor\SSL\ClientComponent\2_SangforNsp.dll”。模塊已生成,不包含符號。

2.3.4         長連接調用兩次不同的url

如下圖所示,長連接調用兩個不同的url。會創建兩個socket連接。不會因為切換不同的url,重新創建socket連接。對於每個url會對應一個socket連接。用時82秒,之前分別調用url1和url2所用的時間之和是27+40=67秒,多出來的15秒時間,應該是連接之間的切換時間,所以為了減少時間,可以一種url,用一個curl對象,避免切換。

 

WSPStartup ===> D:\Project\CurlHighSpeed\Win32\Release\CurlHighSpeed.exe使用鏈式SPI[WSPConnect] Socket ip 127.0.0.1:58345[WSPConnect] Socket ip 127.0.0.1:58347

 

2.3.5         總結分析

調用情況

用時

connect連接次數

請求次數

單次用時

Shot連接url1

147秒

1000次

1000

0.147

Long連接url1

27秒

1次

1000

0.027

Long 調用url2

40秒

1次

1000

0.04

Long url1和url2

82秒

2次

2000

0.041

綜上所述可以得出結論:

(1)   curl初始化,設置參數、調用url、清理cleanup,整個過程會創建一個socket連接。可以先創建,設置為長連接,不清理cleanup,重復使用該curl對象,復用已創建的curl對象和socket連接。可以提高5倍的速度。

(2)   調用不同的url,會因為服務器性能和請求數據量,耗時也會不同。

(3)   一個長連接curl調用兩個不同的url(不同的網址),會創建兩個socket連接。保持兩個socket長連接。不會因為切換不同的url,而重復創建socket連接。切換連接會造成耗時,降低速度20%左右。所以對不同的url,可以用不用的對象和連接,避免切換。提高性能。

2.3.6       源碼下載

 https://download.csdn.net/download/baochunlei1/12863616

3. libcurl多線程高並發

 

 

3      curl線程池並發執行

多線程一直是提高性能和速度的關鍵技術,繼承QT的QRunable類,定義一個線程任務,用QThreadPool線程池去調用url;

3.1  測試程序

采用如下的程序進行測試,采用毫秒計時。

3.1.1         測試主程序

#include <QtCore/QCoreApplication>

#include"RestClientPool.h"

#include "RestClient.h"

#include <QDateTime>

#include <string>

#include <QThreadPool>

#include "MultTask.h"

extern  RestClientPool g_restpool;

using namespace std;

//RestClientPool g_restPool;

int main(int argc, char *argv[])

{

    QCoreApplication a(argc, argv);

    ///CHttpClient m_shotclient;

    RestClientPool m_longClient;

    QDateTime StartTime = QDateTime::currentDateTime();

    qint64 istarttimems = StartTime.toMSecsSinceEpoch();

    /*string strUrl = "http://qt.gtimg.cn/q=sz002415";

    string strUrl2= "http://hq.sinajs.cn/list=sz002415";

    string strResponse = "";

    for (int i=0;i<1000;i++)

    {

        m_longClient.Get(strUrl2, strResponse);

        m_longClient.Get(strUrl, strResponse);

    }*/

    QThreadPool qThreadPool;

    qThreadPool.setMaxThreadCount(10);

    for (int i=0;i<1000;i++)

    {

        MultTask * p = new MultTask();

        qThreadPool.start(p);

    }

    qThreadPool.waitForDone();

    QDateTime timeEnd = QDateTime::currentDateTime();

    qint64 iendtimems = timeEnd.toMSecsSinceEpoch();

    int time = iendtimems - istarttimems;

    //int time = timeEnd.toTime_t()- StartTime.toTime_t();

    printf("using time %d\n", time);

    printf("curl number %d\n ",g_restpool.getcurlsize());

    return a.exec();

}

3.1.2         線程類定義

線程類頭文件

#ifndef MULTTASK_H

#define MULTTASK_H

 

#include <QObject>

#include <QRunnable>

#include "RestClientPool.h"

 

 

class MultTask : public QObject,public QRunnable

{

    Q_OBJECT

 

public:

    MultTask();

    ~MultTask();

    void run();

private:

   

};

 

#endif // MULTTASK_H

線程類源文件

#include "MultTask.h"

#include<string>

using namespace std;

RestClientPool g_restpool;//全局變量

 

 

MultTask::MultTask()

{

    setAutoDelete(true);

}

 

MultTask::~MultTask()

{

 

}

 

void MultTask::run()

{

    string strUrl = "http://qt.gtimg.cn/q=sz002415";

    string strResponse = "";

    g_restpool.Get(strUrl,strResponse);

}

1.1.3         運行測試結果

如下圖所示,采用10個線程去調用1000次url1。用時3868毫秒。創建curl的數量是10個,創建的socket連接的數量是10個。平均每次調用時間是0.003868秒。而單線程平均每次調用耗時0.027秒。按理說10個線程,每次調用應該是0.0027秒,但是0.003868秒大於0.0027秒。線程之間的資源競爭和切換也會耗時。而且1000次調用接口中會出現不定數量的錯誤6,錯誤碼解釋是CURLE_COULDNT_RESOLVE_HOST(6)無法bai解析主機。給定的遠程主機沒有得到解決。可能是多線程訪問太快,服務器無法響應。

 

輸出框中顯示的創建的10個socket連接:

WSPStartup ===> D:\Project\CurlHighSpeed\Win32\Release\CurlHighSpeed.exe使用鏈式SPI[WSPConnect] Socket ip 127.0.0.1:54517[WSPConnect] Socket ip 127.0.0.1:54518[WSPConnect] Socket ip 127.0.0.1:54520[WSPConnect] Socket ip 127.0.0.1:54522[WSPConnect] Socket ip 127.0.0.1:54524[WSPConnect] Socket ip 127.0.0.1:54525[WSPConnect] Socket ip 127.0.0.1:54527[WSPConnect] Socket ip 127.0.0.1:54531[WSPConnect] Socket ip 127.0.0.1:54533[WSPConnect] Socket ip 127.0.0.1:54536WSPStartup ===> D:\Project\CurlHighSpeed\Win32\Release\CurlHighSpeed.exe[WSPConnect] Socket ip 127.0.0.1:54540[WSPConnect] Socket ip 127.0.0.1:54539[WSPConnect] Socket ip 127.0.0.1:54542[WSPConnect] Socket ip 127.0.0.1:54544[WSPConnect] Socket ip 127.0.0.1:54546[WSPConnect] Socket ip 127.0.0.1:54551[WSPConnect] Socket ip 127.0.0.1:54553“CurlHighSpeed.exe”

3.1.4         不同線程數量調用耗時

為了研究線程數量和調用耗時的關系,采用不同的線程數量去執行10000次的調用;每次消耗的時間如下所示。隨着線程數量的增加,多線程處理速度和性能會大幅提高。但是當線程數量達到一定數量之后,線程池的性能反而下降,這是因為線程之間的競爭資源和線程CPU切換導致的。

線程數量

總用時(ms)

每次用時(ms)

Curl數量

錯誤數

10

27690

2.7690

10

6

20

18080

1.808

20

8

50

9593

0.9593

50

7

100

6200

0.62

100

9

200

7183

0.7183

200

19

300

12431

1.2431

300

11

400

11687

11687

400

12

500

21990

2.1990

500

13

3.1.5 測試程序源碼下載地址

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM