亚洲成精品动漫久久精久,九九在线精品视频播放,黄色成人免费观看,三级成人影院,久碰久,四虎成人欧美精品在永久在线

掃一掃
關(guān)注微信公眾號

64位windows常規(guī)編程簡介
2007-03-19   微軟

性能和可伸縮性

為了可以伸縮,您必須了解這對于您特定的方案意味著什么。例如,對于 Web 服務(wù)器,可伸縮性意味著可以為與所連接的用戶數(shù)量相關(guān)的頁面提供服務(wù)。請將其考慮為線圖表。

498)this.style.width=498;">
圖1.線性比例示例

隨著用戶數(shù)量的增加,每秒的頁面數(shù)量也應(yīng)該增加。上圖顯示了一個線性比例。當(dāng)用戶數(shù)量達到 3 倍時,每秒提供的頁面也相應(yīng)增加。

另一個比例的定義與硬件相關(guān)。如果我將系統(tǒng)上的處理器數(shù)量增加一倍,那么我的 Web 服務(wù)器是否也會將輸出增加一倍呢?RAM 或磁盤等情況如何呢?應(yīng)用程序也需要根據(jù)這個想法設(shè)計。您所創(chuàng)建的線程數(shù)量應(yīng)該基于系統(tǒng)中的處理器數(shù)量以及每個線程進行的工作類型。用于緩存網(wǎng)頁內(nèi)容的內(nèi)存量應(yīng)該與可用于應(yīng)用程序的內(nèi)存量成一定比例,等等。這個概念通常被稱為“向上擴展”。如果我將框構(gòu)建得越來越大,那么可以相應(yīng)的生成越來越多嗎?

伸縮的其他形式是當(dāng)您談?wù)摲植际接嬎慊蚍?wù)器場時。這通常被稱為“向外伸縮”。如果我將服務(wù)器場中的計算機數(shù)量增加一倍,那么我的輸出也會增加一倍嗎?

當(dāng)設(shè)計可伸縮的系統(tǒng)時,需要考慮這些方案。當(dāng)前,硬件變得越來越大(Itanium 最多支持 64 個處理器計算機),因此向上擴展需要在開發(fā)人員頭腦中處于最重要的位置。如果您的圖表轉(zhuǎn)為水平、甚至隨著您增加資源開始下降,這尤為正確。如果整個系統(tǒng)的某個部分無法伸縮,它可能會對整個系統(tǒng)產(chǎn)生負面的影響。

線程:如何有效地使用它們

在線程間分割您的工作可以簡化代碼,在多處理器系統(tǒng)上可以使您的代碼更有效,但是如果您不知道自己在做什么的話,還會降低性能和可伸縮性。例如,如果應(yīng)用程序中的所有線程都需要獲得相同的全局關(guān)鍵部分,那么對該關(guān)鍵部分的爭用可能會使您的線程花費其大部分休眠時間。它還可能導(dǎo)致發(fā)生過多的上下文轉(zhuǎn)換,進而可能會引起應(yīng)用程序占用系統(tǒng)內(nèi)核中相當(dāng)比例的處理時間,甚至根本沒有運行您的代碼。如果在多處理器的系統(tǒng)上,這些問題會尤其糟糕,您額外的處理器可能會結(jié)束當(dāng)前閑置,等待訪問共享數(shù)據(jù)。

要使用的線程的理想數(shù)量等于系統(tǒng)中處理器的數(shù)量。如果您的線程相互獨立并受到處理器的限制,那么它們應(yīng)該能夠每次都消耗掉其整個時間片。如果您具有可能執(zhí)行阻止操作的線程,那么您可能希望增加線程的數(shù)量,以便當(dāng)一個線程休眠時,另一個線程可以取代其位置。您將要確定線程阻塞的位置及頻率。意識到這一點后,您就可以知道應(yīng)該運行的線程數(shù)量。您始終要為每個處理器準(zhǔn)備好一個線程。否則,您就浪費了處理能力。當(dāng)然,這些僅僅是指導(dǎo)原則,并且確定應(yīng)用程序是否以盡可能高的效率運行的唯一方法就是對其進行分析和測試。

異步 I/O:不會阻塞等待數(shù)據(jù)

基于 NT 內(nèi)核的 Windows 系統(tǒng)支持異步 I/O,又稱重疊的 I/O。大多數(shù)形式的 I/O 都可以異步完成。這包括文件 I/O 和網(wǎng)絡(luò) I/O。對于文件 I/O,您可以使用 ReadFile/WriteFile API。當(dāng)讀/寫時,通過借助 FILE_FLAG_OVERLAPPED 標(biāo)記打開文件并指定 OVERLAPPED 結(jié)構(gòu),您將使系統(tǒng)在 I/O 完成時通知您。這使您可以在等待的過程中完成其他工作。對于使用 Windows Socket (WinSock) 的網(wǎng)絡(luò) I/O,您可以使用 WSASocket 創(chuàng)建套接字,并指定 WSA_FLAG_OVERLAPPED 標(biāo)記,然后當(dāng)調(diào)用 WSARecv/WSASend API 時,您可以指定一個 OVERLAPPED 結(jié)構(gòu)或一個回調(diào)函數(shù)。當(dāng)您編寫網(wǎng)絡(luò)服務(wù)器時,異步 I/O 尤為有效。您可以將多個接收請求“排入隊列”,然后去休息,等待其中一個完成。當(dāng)一個完成時,就會處理傳入的數(shù)據(jù),然后將另一個接收“排入隊列”。這比使用 select API 來輪詢數(shù)據(jù)好得多,并且它可以更有效地使用系統(tǒng)資源。

等待異步 I/O 請求完成有幾種選項:

調(diào)用 GetOverlappedResult API

在發(fā)出異步 I/O 請求后,您可以使用 GetOverlappedResult API 來輪詢請求的狀態(tài),或者僅僅等待請求的完成。當(dāng)請求完成時,GetOverlappedResult 將返回請求過程所傳輸?shù)淖止?jié)數(shù)。

使用 HasOverlappedIoCompleted

您可以使用 HasOverlappedIoCompleted 宏來有效地進行輪詢與 OVERLAPPED 結(jié)構(gòu)相關(guān)聯(lián)的請求是否已經(jīng)完成。請求完成后,您就可以使用 GetOverlappedResult API 來獲得有關(guān)請求的更多信息(例如傳輸?shù)淖止?jié)數(shù))。

指定 OVERLAPPED 結(jié)構(gòu)中的事件

通過在 OVERLAPPED 結(jié)構(gòu)的 hEvent 字段中指定一個事件,您可以執(zhí)行自己的輪詢或等待請求的完成,方法是在對 WaitForSingleObject 或 WaitForMultipleObjects 的調(diào)用中指定一個事件。當(dāng)重疊操作完成時,內(nèi)核將發(fā)信號通知該事件。

將內(nèi)核對象綁定到 I/O完成端口

I/O 完成端口是系統(tǒng)提供的非常有用的工具。有關(guān)信息,請參閱下面的部分。對于事件驅(qū)動的系統(tǒng)(例如網(wǎng)絡(luò)服務(wù)器等待輸入),I/O 完成端口提供了用于等待和處理傳入事件的完美機制。

I/O 完成端口:事件驅(qū)動 I/O

大多數(shù) Windows 開發(fā)人員都熟悉窗口消息和消息隊列。將 I/O 完成端口理解為高性能、高可伸縮性的超級消息隊列。如果您具有一個事件驅(qū)動的系統(tǒng),則您需要使用完成端口。完成端口從根本上設(shè)計用于提供性能。如果您從頭開始編寫代碼,您絕對應(yīng)該使用 I/O 完成端口。它們要求進行一些嘗試才能正確完成,但是只要您熟悉了它們的工作方式,使用起來就會非常簡單。如果從另一個系統(tǒng)或使用異步 I/O 的代碼庫遷移應(yīng)用程序,那么您必須提前完成一些工作,但由此帶來的好處證明所做的努力是完全值得的。

您可以使用 CreateIoCompletionPort API 來創(chuàng)建完成端口。這也是您用于關(guān)聯(lián)內(nèi)核對象與完成端口的 API。在文件句柄或套接字句柄與完成端口相關(guān)聯(lián)后,在該句柄上完成的所有 I/O 請求都將排列到完成端口隊列中。

通知可以被排列到完成端口隊列中,或者按照先進先出 (FIFO) 順序進行處理。您還可以使用 PostQueuedCompletionStatus API 將自定義的通知排列到完成端口隊列中。使用這個自定義通知方法是一個很好的方法,用于向線程發(fā)出信號通知其關(guān)機或插入任何其他自定義外部事件。在下面的示例代碼中,PostQueuedCompletionStatus 用于通知工作線程退出:

HRESULT StopCompletionThreads()

{

// Tell the threads that were started, to shut down

for (size_t i = 0; i < COMPLETION_THREAD_COUNT; i++)

{

assert(g_completionThreads[i]);

PostQueuedCompletionStatus(g_completionPort, 0, 0, NULL);

}

// Wait for the threads to shutdown

WaitForMultipleObjects(

COMPLETION_THREAD_COUNT,

g_completionThreads,

TRUE,

INFINITE);

// Close the handle for each thread

for (size_t i = 0; i < COMPLETION_THREAD_COUNT; i++)

{

CloseHandle(g_completionThreads[i]);

g_completionThreads[i] = NULL;

}

return S_OK;

}

請注意,為 dwNumberOfBytesTransferred 和 dwCompletionKey 參數(shù)傳遞零,而為 OVERLAPPED 參數(shù)傳遞 NULL。這些組合的值是工作線程檢查用于關(guān)機的值:

UINT __stdcall CompletionThread(PVOID param)

{

BOOL result = FALSE;

OverlappedBase* overlapped = NULL;

ULONG_PTR key = 0;

DWORD numberOfBytes = 0;

for (;;)

{

result = GetQueuedCompletionStatus(

g_completionPort,

&numberOfBytes,

&key,

(OVERLAPPED**)&overlapped,

INFINITE);

if (result)

{

if (numberOfBytes == 0 && key == 0 && !overlapped)

break;

OverlappedCallback callback =

overlapped->callback;

callback(

NO_ERROR,

numberOfBytes,

key,

overlapped);

}

else

{

if (overlapped)

{

OverlappedCallback callback =

overlapped->callback;

if (callback)

{

callback(

GetLastError(),

numberOfBytes,

key,

overlapped);

}

}

}

}

return 0;

}

I/O 完成方法的核心是 OVERLAPPED 結(jié)構(gòu)。OVERLAPPED 結(jié)構(gòu)包含特定于每個 I/O 請求的上下文信息。通常情況下,將結(jié)構(gòu)進行擴展以添加自己的上下文信息。當(dāng)處理完成通知時,可以獲得對該結(jié)構(gòu)(以及您的上下文數(shù)據(jù))的訪問。

通過從 OVERLAPPED 結(jié)構(gòu)繼承或?qū)⑵浒樽约航Y(jié)構(gòu)的第一個字段來擴展 OVERLAPPED 結(jié)構(gòu),如下所示:

//C++

struct OverlappedBase : public OVERLAPPED

{

OverlappedCallback callback;

};

或者

//C

struct OverlappedBase

{

OVERLAPPED overlapped;

OverlappedCallback callback;

};

OVERLAPPED 結(jié)構(gòu)包含下列字段:

typedef struct _OVERLAPPED {

ULONG_PTR Internal;

ULONG_PTR InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

當(dāng)讀取文件或?qū)懭胛募r,Offset 和 OffsetHigh 字段用于指定偏移量。Internal 字段包含操作的狀態(tài)(或錯誤)。InternalHigh 字段包含在 I/O 請求過程中傳輸?shù)淖止?jié)數(shù)。在 GetOverlappedResult 返回 TRUE(或者完成通知排列到完成端口隊列中)之前,Internal 和 InternalHigh 字段都是無效的。

可以擴展該結(jié)構(gòu)以包括您可能需要的任何其他字段。但是,請牢記,結(jié)構(gòu)必須在 I/O 請求的生存期中保持可用。

下面的代碼片段顯示了 OVERLAPPED 和 OverlappedBase 結(jié)構(gòu)是如何為網(wǎng)絡(luò) I/O 操作進行擴展的:

#define SOCKET_BUFFER_SIZE     128

#define SOCKOP_ACCEPT 1

#define SOCKOP_RECV 2

#define SOCKOP_SEND 3

struct SocketOverlapped

{

OverlappedBase base;

int op;

SOCKET sock;

DWORD numberOfBytes;

DWORD flags;

BYTE buffer[SOCKET_BUFFER_SIZE];

};

這允許每個請求信息可以與已啟動的每個 I/O 請求一起存儲。op 字段存儲正在啟動、發(fā)送、接收或接受的操作。numberOfBytes 字段包含有效的(用于發(fā)送或接收)buffer 字段中的字節(jié)數(shù)。

劃分和征服:讓線程獨立工作

可伸縮性的弊端在于爭用。例如,當(dāng)一個線程必須等待另一個線程以獲取鎖定時,該線程就在浪費時間,并且潛在地可以完成的工作必須等待。這會引起線程關(guān)系和非一致的內(nèi)存訪問 (NUMA)。如果您的處理可以在線程之間進行分割(在線程之間沒有實際的依存關(guān)系),那么可以將每個線程鎖定到其自己的處理器上。在 NUMA 系統(tǒng)上,您還可以分割每個線程使用的內(nèi)存,這樣對于 NUMA 節(jié)點,內(nèi)存是本地的。

線程關(guān)系

Windows Server 2003 使您可以指定允許某個線程在哪個處理器上運行。這稱為設(shè)置線程的處理器關(guān)系。您可以使用 CODE>SetThreadAffinityMask/GetThreadAffinityMask 函數(shù)來進行設(shè)置并檢查特定線程的關(guān)系。設(shè)置線程的關(guān)系在降低處理器間總線通訊方面很有用。當(dāng)線程從一個處理器移動到另一個處理器時,當(dāng)前處理器的緩存必須與新的處理器進行同步。處理器之間的線程跳轉(zhuǎn)可能會引起性能問題。另外,某些系統(tǒng)使您可以將特定的設(shè)備中斷綁定到特定的處理器。在您的軟件中,您可以將特定的線程“綁定”到該處理器,并且從該線程發(fā)出/處理該設(shè)備的所有 I/O,因此通過增加潛在的系統(tǒng)并發(fā)(即,在多處理器之間快速傳播如網(wǎng)卡這樣的活動設(shè)備)。

NUMA

NUMA 表示非一致的內(nèi)存訪問。在傳統(tǒng)的對稱多處理 (SMP) 系統(tǒng)上,系統(tǒng)中的所有處理器對整個范圍的物理內(nèi)存具有相同的訪問權(quán)限。傳統(tǒng) SMP 系統(tǒng)的問題在于添加越多的處理器和內(nèi)存,總線通訊量就會越高。也就會抑止性能。在 NUMA 系統(tǒng)上,處理器分組成較小的系統(tǒng),每個小系統(tǒng)都有其自己的“本地”內(nèi)存。訪問“本地”內(nèi)存成本很低,然而訪問另一個節(jié)點上的內(nèi)存代價可能會非常昂貴。Windows 將嘗試在正在使用內(nèi)存的節(jié)點上計劃線程,但是可以使用 NUMA 函數(shù)來改進線程計劃和內(nèi)存使用情況來幫助 Windows。使用下列功能來確定哪個處理器屬于哪個節(jié)點,以及為特定的處理器/節(jié)點設(shè)置線程的關(guān)系:

GetNumaHighestNodeNumber

GetNumaProcessorNode

GetNumaNodeProcessorMask

SetThreadAffinityMask

另外,大量利用內(nèi)存的應(yīng)用程序可以使用以下函數(shù)來改進它們在 NUMA 系統(tǒng)上的內(nèi)存使用情況:

GetNumaAvailableMemoryNode

開始考慮 NUMA 和大型多處理器系統(tǒng)以及從頭開始為它們進行設(shè)計是非常重要的。大多數(shù)最初的 64 位部署都將用于大型多處理器系統(tǒng),該系統(tǒng)的處理器多于 8 個,運行諸如 Secure Audio Path (SAP) 這樣的巨型企業(yè)應(yīng)用程序。NUMA 對于整體可伸縮性和性能非常關(guān)鍵。

WinSock Direct

在大型的數(shù)據(jù)中心中,服務(wù)器之間的通信量可能會超出傳統(tǒng)基于 TCP/IP 網(wǎng)絡(luò)的帶寬。通過卸載一些來自 CPU 的網(wǎng)絡(luò)協(xié)議處理,系統(tǒng)區(qū)域網(wǎng) (SAN) 設(shè)計用于解決這個問題。在服務(wù)器之間提供更快速的通訊對服務(wù)器應(yīng)用程序很有好處,這樣就改進了向外擴展解決方案的性能。大多數(shù) SAN 要求直接針對供應(yīng)商的 API 編寫應(yīng)用程序,這就導(dǎo)致很少有應(yīng)用程序可以用于在 SAN 環(huán)境中進行部署。Microsoft 開發(fā)的 Windows Sockets (WinSock) Direct 針對低級 SAN 實現(xiàn)提供了一個通用編程接口。WinSock Direct 位于標(biāo)準(zhǔn) WinSock API 下,但是繞過了內(nèi)核網(wǎng)絡(luò)層直接與 SAN 硬件進行對話。因為 WinSock Direct 位于現(xiàn)有的 WinSock API 下,所以 IT 部門可以在 SAN 環(huán)境中部署應(yīng)用程序,而無需對應(yīng)用程序進行修改。

SAN 通過兩種標(biāo)準(zhǔn)的傳輸模式,提供了可靠的、順序的數(shù)據(jù)提交,這兩種模式是:消息和遠程直接內(nèi)存訪問 (RDMA)。消息很像傳統(tǒng)的網(wǎng)絡(luò)協(xié)議,其中數(shù)據(jù)包發(fā)送到某個對等方,而該對等方會從網(wǎng)絡(luò)中請求數(shù)據(jù)包。RDMA 允許指定數(shù)據(jù)包的目標(biāo)緩沖區(qū)。

通常情況下,SAN 硬件將直接在硬件中實現(xiàn)大部分其數(shù)據(jù)傳輸功能。這使得 SAN 實現(xiàn)可以完成諸如繞過內(nèi)核這樣的操作。通常由內(nèi)核提供的處理直接卸載到硬件中。

WinSock Direct 避免了應(yīng)用程序直接編程到 SAN 特定的 API 的要求。只通過安裝 SAN 硬件以及為硬件安裝 WinSock Direct 驅(qū)動程序,現(xiàn)有的應(yīng)用程序就可以利用由 SAN 提供的更高的性能。

熱詞搜索:

上一篇:2000、XP、2003所有注冊表設(shè)置 4
下一篇:安騰64位技術(shù)概述

分享到: 收藏