2011年9月16日 星期五

[ASP.NET] Performance Tuning

1. 使用 SqlCommand 搭配 SqlDataReader 時,記得先呼叫 SqlCommand.Cancel() 再呼叫 SqlDataReader.Close(),順序錯誤效能會低落很多
    (若僅呼叫 SqlDataReader.Close() 效能也會很低落)

2. 資料來源控制項的 DataSourceMode 要根據實際需求選擇
    (選擇 DataSet 模式,功能雖然強大,但耗費資訊)

3. 處理大量資料避免使用 ADO.NET Entity Framework 這一類的工具,速度很慢

2011年8月3日 星期三

[.NET] 如何不安裝 Oracle Client 並與 Oracle DB 連線

恩.......我目前手邊這一台 NB 真的很怪....無法安裝 Oracle Client....

但是我要連 Oracle 阿!! 這該怎辦ㄌㄟ....

上網找了一下,必須要在程式執行目錄(bin/)中,放入以下五個 DLL 檔案:

  1. Oracle.DataAccess.dll
  2. oci.dll 
  3. OraOps11w.dll
  4. oraociei11.dll
  5. msvcr71.dll
這些檔案可以在有安裝 Oracle Client 的電腦上找到....我是請同事找給我的.....


另外在連線字串部分,沒辦法使用 OracleDBConnectionStringBuilder 物件產生連線字串,必須用自行組成語法的方式:
string DBConnectionString = @"Data Source=(DESCRIPTION = (ADDRESS_LIST =
                                    (ADDRESS = (PROTOCOL = TCP)(HOST = 這是 Oracle Server IP)(PORT = 1521)) )
                                    (CONNECT_DATA = (SID = 這裡放SID)(SERVER = DEDICATED) ) )
                                    ;Persist Security Info=True;User ID=這是使用者帳號;Password=使用者密碼;";

最後程式中引用 Oracle.DataAccess.dll 作為參考,相關的 Oracle API 就可以使用囉!


2011年6月1日 星期三

[LINQ] 集合已修改; 列舉作業可能尚未執行??

今天同事在寫程式遇到這問題.....

問我.... LINQ 可以在 multi-thread 環境下執行嗎?? 程式起來一直有問題......

我心裡想......怎麼會不行? 如果不行,微軟不就搞了一個大飛機了..........?

後來發現其實跟 LINQ 無關,而是在進行列舉作業時不能去修改集合的值

[JVM] Performance Tuning 相關資源蒐集

JVM調優總結- See World - ITeye技術網站

JVM調優總結(一)-- 一些概念- 和你在一起- ITeye技術網站

JVM調優總結(二)-一些概念- 和你在一起- ITeye技術網站

JVM調優總結(三)-基本垃圾回收算法- 和你在一起- ITeye技術網站

JVM調優總結(四)-垃圾回收面臨的問題- 和你在一起- ITeye技術網站

JVM調優總結(五)-分代垃圾回收詳述1 - 和你在一起- ITeye技術網站

JVM調優總結(六)-分代垃圾回收詳述2 - 和你在一起- ITeye技術網站

JVM調優總結(七)-典型配置舉例1 - 和你在一起- ITeye技術網站

JVM調優總結(八)-典型配置舉例2 - 和你在一起- ITeye技術網站

JVM調優總結(九)-新一代的垃圾回收算法- 和你在一起- ITeye技術網站

JVM調優總結(十)-調優方法- 和你在一起- ITeye技術網站

JVM調優總結(十一)-反思- 和你在一起- ITeye技術網站

JVM調優總結(十二)-參考資料- 和你在一起- ITeye技術網站

2011年5月31日 星期二

[Windows] 修改 JVM 啟動參數

今天早上為了 H2 執行五六個小時後會出現 out of memory 的問題在頭痛...

上到 Google Group 查了一下,有人建議先把 JVM 的 heap 開大一點試試看....

於是.......問題來了,要怎麼開大??

在 Linux 裡面可以直接透過 Alias 的方式解決.......

那 Windows 呢? 答案就是設定一個名稱為 "_JAVA_OPTIONS" 的環境變數

值的部分就設定為 "-Xms512m -Xmx1024m" 應該是很夠用了....

再來繼續長時間測試 H2 看看.....

2011年5月30日 星期一

[HTML5] 學習資源

基本觀念

教學(投)影片

工具

2011年5月26日 星期四

[LINQ] 如何直接更改物件集合中的物件值而不建立新物件

用過 LINQ 的人應該會對 LINQ 處理資料集合的功力印象深刻....

但....LINQ 是 Query 阿! 不是 Update!

那如果我只是要針對物件集合中的某幾個物件進行值的變更.......要怎麼作呢....??

答案是 => 只要自己撰寫一個 extension method,method 中回傳原本的物件集合

在網路上找到一個很不錯的參考範例連結:
LINQ: Select an object, but change some properties without creating a new object (Rob Volk's Blog)


以下寫了一個簡單的 sample


但有一點真的需要注意的是,這種方式只能用在物件集合中,若是用在基本型態的資料集合中(例如:整數陣列、整數 List) 則沒有效果......


2011/06/08 Updated: 

今天有找到初始化陣列的方式囉! 只要使用 extension method 就可以簡單達成了....以下為範例:

2010年8月31日 星期二

2010年3月12日 星期五

[Linux Programming] 在 Ubuntu 中使用 C 語言連結 MySQL

首先.......必須安裝 MySQL server,一般來說安裝 "mysql-server" 都可以裝到目前最新版的套件

接著要安裝開發程式所需要的 library:

Ubuntu 8.04 => libmysqlclient15-dev

相關的 header 檔案都會放在 /usr/include/ 裡面,而實際運作的函式庫則會存在 /usr/lib/mysql 中

若是撰寫 mysql 相關程式時,編譯方式如下:

gcc <程式名稱> -I /usr/include/mysql -L /usr/lib/mysql -l mysqlclient -o <輸出檔案名稱>

2010年3月9日 星期二

[Git] 在 Windows 上使用 Git

Git 聽說是比 cvs, subversion 還好用的 version control system 阿!!

為何要用 Git 阿?? 因為優點很多阿! 詳細說明可以看 => Why Git is Better Than X  這一篇文章~

Git 大概有以下特色:
  1. 每個 local 端都有自己的 repository

  2. 特色為 branch + merge

  3. 適合開發人數眾多的大型專案(當然小型專案也是沒有問題滴)


大部分使用 git 的人都是在 Linux 的平台上使用,但要怎麼在 Windows 上面使用呢?

簡單說明步驟如下:
  1. 下載 Windows 用的 git 核心程式,在 git 官網上為 msysgit

  2. 在所要進行版本管理的資料夾上按滑鼠右鍵,選擇 Git Bash Here

  3. 接著會跳出一個模擬 bash 環境的視窗,接著就可以跟 Linux 一樣開始使用 Git 囉!


===== 以下說明最基本的使用方式 =====

#初始化 local repository
> git init

#將目錄中的檔案全部加入 Staging Area
> git add .

#將 Staging Area 中的檔案加入 local repository 中
> git commit -a

#移動至 master branch (正常狀況下 branch 會預設在 master)
> git checkout master

#將資料 push 至遠端的 repository (以 gitorious 為例)
> git remote add origin <git push url>
> git push origin master


【備註】
在將檔案 push 到遠端 git server 之前,需要把加密用的 key pair 準備好,可以透過以下指令產生:
> ssh-keygen -rsa
接著把兩個檔案都放到 C:\Documents and Settings\<USER NAME>\.ssh ,並將 public key 的內容加入到 gitorious 的網站上即可。


相關連結


2010年3月7日 星期日

[Linux Programming] 在 Ubuntu 中使用 dbm 資料庫

在 ubuntu 中 dbm 相關開發套件是不會預先安裝的,因此如果要使用的話,必須安裝「libgdbm-dev」套件。

而由於安裝的是 gdbm 套件,若要使用 gdbm 的相關函式當然沒問題,但若是要使用 ndbm 的相關函式,則必須進行相容性的轉換,作法如下:
  1. 在程式中 include gdbm-ndbm.h

  2. 編譯時加上 -l gdbm_compat -l gdbm 兩個參數以連結函式庫
函式庫說明可以參考以下連結:

2010年3月1日 星期一

[C#] Socket Programming

socket programming 的重點大概有幾個:
  1. 有 server & client 兩端
  2. server 只有一個,而 client 有可能會多個
  3. server 可設定監聽(listen)的 port number


以下直接用範例來說明囉!
(其中 SocketServer 跟新的 client 連線後,會交給 ClientRequestHandler 處理)

SocketServer.cs
using System;
using System.Collections.Generic;
using System.Text;

using System.Net.Sockets;
using System.Net;
using System.ComponentModel;

namespace SocketConn
{
    class SocketServer
    {
        #region private property

        ///         /// socket server TCP port number
        ///         private int _PortNumber;


        ///         /// TCP Listener
        ///         private TcpListener _Listener;


        ///         /// 用來處理 Listener 工作的執行緒
        ///         private BackgroundWorker _bgwServer = new BackgroundWorker();


        ///         /// socker client 識別編號
        ///         private int _ClientNo = 0;

        #endregion


        #region static public property

        ///         /// 工作進行中產生之訊息
        ///         public static List sMessages = new List();

        #endregion


        #region constructor

        ///         /// constructor
        ///         /// 
socket server TCP port number
        public SocketServer(int inPortNumber)
        {
            this._PortNumber = inPortNumber;

            //委派事件
            _bgwServer.DoWork += new DoWorkEventHandler(_bgwServer_DoWork);
        }

        #endregion


        #region public method

        ///         /// 開始監聽
        ///         public void Start()
        {
            if (!_bgwServer.IsBusy)
                _bgwServer.RunWorkerAsync();
        }

        #endregion


        #region BackgroundWorker

        /// 
        /// 處理 Listener 工作
        ///         /// 

        /// 

        private void _bgwServer_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                //若 TCP Listner 正在工作,則停止
                if (_Listener != null)
                    _Listener.Stop();

                //初始化 TCPListener
                _Listener = new TcpListener(IPAddress.Any, _PortNumber);

                //啟動 listener
                _Listener.Start();
                sMessages.Add(" >> " + "Server Started");

                //========== 持續接受監聽 socket client 的連線 ========== (start)
                while (true)
                {
                    //監聽到來自 socket client 的連線要求
                    TcpClient socket4Client = _Listener.AcceptTcpClient();

                    //累加 socket client 識別編號
                    _ClientNo++;
                    sMessages.Add(" >> " + "Client Request No:" + Convert.ToString(_ClientNo) + " started!");

                    //產生 BackgroundWorker 負責處理每一個 Socket Client 的要求
                    ClientRequestHandler handler = new ClientRequestHandler(_ClientNo, socket4Client);
                    handler.DoCommunicate();
                }
                //========== 持續接受監聽 socket client 的連線 ========== (end)
            }
            catch (Exception exp)
            {
                sMessages.Add(exp.ToString());
            }
        }

        #endregion
    }
}


ClientRequestHandler.cs
using System;
using System.Collections.Generic;
using System.Text;

using System.Net.Sockets;
using System.ComponentModel;

namespace SocketConn
{
    class ClientRequestHandler
    {
        #region private property

        ///         /// socket client 識別號碼
        ///         private int _ClientNo;


        ///         /// socket client reuqest
        ///         private TcpClient _TcpClient;

        #endregion


        #region constructor

        ///         /// constructor
        ///         /// 
socket client 識別號碼
        /// 
socket client reuqest
        public ClientRequestHandler(int inClientNo, TcpClient inTcpClient)
        {
            this._ClientNo = inClientNo;
            this._TcpClient = inTcpClient;
        }

        #endregion


        #region public method

        ///         /// server & client 間相互進行通訊
        ///         public void DoCommunicate()
        {
            //產生 BackgroundWorker 負責處理每一個 socket client 的 reuqest
            BackgroundWorker bgwSocket = new BackgroundWorker();
            bgwSocket.DoWork += new DoWorkEventHandler(bgwSocket_DoWork);
            bgwSocket.RunWorkerAsync();
        }

        #endregion


        #region BackgroundWorker

        ///         /// 處理 socket client request
        ///         private void bgwSocket_DoWork(object sender, DoWorkEventArgs e)
        {
            //server & client 已經連線完成
            while (_TcpClient.Connected)
            {
                //取得網路串流物件,取得來自 socket client 的訊息
                NetworkStream netStream = _TcpClient.GetStream();
                byte[] readBuffer = new byte[1024];
                int count = 0;
                if ((count = netStream.Read(readBuffer, 0, readBuffer.Length)) != 0)
                {
                    string clientRequest = Encoding.UTF8.GetString(readBuffer, 0, count);
                    SocketServer.sMessages.Add(" >> " + "From client(" + _ClientNo + ") =>" + clientRequest);

                    //正確取得 client requst,再回傳給 client
                    string serverResponse = "Server to clinet(" + _ClientNo + ") => message: " + clientRequest;
                    byte[] sendBytes = Encoding.UTF8.GetBytes(serverResponse);
                    netStream.Write(sendBytes, 0, sendBytes.Length);
                    netStream.Flush();
                    SocketServer.sMessages.Add(" >> " + serverResponse);
                }
            }
        }

        #endregion
    }
}


SocketClient.cs
using System;
using System.Collections.Generic;
using System.Text;

using System.Net;
using System.Net.Sockets;

namespace SocketConn
{
    class SocketClient
    {
        #region private property

        ///         /// 遠端 socket server IP 位址
        ///         private string _RemoteIpAddress;

        ///         /// 遠端 socket server 所監聽的 port number
        ///         private int _RemotePortNumber;


        ///         /// socket client 物件(連接遠端 socket server 用)
        ///         private TcpClient _TcpClient;

        #endregion


        #region public static property

        public static List sMessages = new List();

        #endregion


        #region constructor

        ///         /// constructor
        ///        /// 
遠端 socket server IP 位址
        /// 
遠端 socket server 所監聽的 port number
        public SocketClient(string inRemoteIpAddr, int inRemotePortNum)
        {
            this._RemoteIpAddress = inRemoteIpAddr;
            this._RemotePortNumber = inRemotePortNum;
        }

        #endregion


        #region public method

        ///         /// 連線至 socket server
        ///         public void Connect()
        {
            //初始化 socket client
            _TcpClient = new TcpClient();
            _TcpClient.Connect(_RemoteIpAddress, _RemotePortNumber);
            sMessages.Add("Client Socket Program - Server Connected ...");
        }


        ///         /// 傳送訊息至 socker server
        ///         /// 
訊息
        /// socker server 回傳結果
        public string Send(string inMessage)
        {
            try
            {
                //取得用來傳送訊息至 socket server 的 stream 物件
                NetworkStream serverStream = _TcpClient.GetStream();

                //將資料轉為 byte[]
                byte[] outStream = System.Text.Encoding.UTF8.GetBytes(inMessage);

                //將資料寫入 stream object (表示傳送資料至 socket server)
                serverStream.Write(outStream, 0, outStream.Length);
                serverStream.Flush();

                //讀取 socket server 回傳值並轉為 string
                byte[] inStream = new byte[10025];
                serverStream.Read(inStream, 0, (int)_TcpClient.ReceiveBufferSize);
                string returndata = System.Text.Encoding.UTF8.GetString(inStream);

                sMessages.Add("Data from Server : " + returndata);
                return returndata;
            }
            catch (Exception exp)
            {
                sMessages.Add(exp.ToString());
                return exp.ToString();
            }
        }

        #endregion
    }
}

2009年10月18日 星期日

[NASM] BIOS 啟動程序

當電腦的電源開啟後,處理器會進入 reset 狀態,此時:
  1. 所有記憶體的內容會變為 0

  2. CS 的值會被預設為 0FFFF[0]H

  3. IP(Instruction Pointer) 儲存指令的 offset,預設為 0

結合 2 & 3(Code Segment + Offset),可以知道第一個要執行的指令的 memory address 為 0FFFF0H(CS:IP),而這個 memory address 即為 BIOS 的進入點。

BIOS 的常式位於 0FFF0H,他檢查各個 I/O port,並對於存在的設備進行初始化,接著 BIOS 會建立兩個資料區:
  1. Interrupt Vector Table (中斷向量表)
    長度為 1 KB,用來做為當 interrupt(中斷) 發生時,BIOS & OS 用來選擇相對應的 interrupt handler 之用,詳細資料可參考此篇文章。

  2. BIOS 資料區
    起始位址為 40[0]H,大小依據設備的多寡而不同。

接著 BIOS 會檢查系統磁碟是否存在,並從系統磁碟下載啟動程式,啟動程式接著從系統磁碟將系統檔案載入 memory,並將控制權交給 OS。

2009年10月9日 星期五

[自動化] 序列埠模擬器(Virtual Serial Port Emulator)

最近開發工作由於沒有實體的設備可以接.....因此要想辦法進行模擬...

而模擬的設備又是走序列埠(serial port),因此只好去找找有沒有免費的模擬器可以用...

上 Google 搜尋「free serial port emulator」

果然給我找到一套免費的可以用 => Free Virtual Serial Ports Emulator

目前的版本是 0.936.4.687,希望這好東西可以持續的推陳出新囉!

我使用的情境如下:

  1. 建立的 Device Type 為 pair (假設為 COM2 + COM3)

  2. Modbus Slave 模擬程式連結 COM2

  3. 程式向 COM3 進行 pooling

這樣就很完美的連結起來啦! 

PS. 這套軟體無法作序列埠的相關設定,例如:Baud Rate。是比較可惜的地方,希望未來可以加入這功能囉!

2009年9月20日 星期日

[OS] Computer System Organization

Computer-System Operation

現今電腦系統中包含了一個或數個 CPU,以及多個連接在 common bus 上個多個 device controller,每種不同的 device controller 用來處理不同的設備,如下圖所示:


CPU 與其他 device controller 可以一起執行,並相互競爭取得 memory cycle;而為了確保不同設備可以依序的存取 shared memory,memory controller 必須提供不同設備同步存取記憶體的方法。

當電腦剛開機時,第一個執行的程式稱為「bootstrap」,而 bootstrap 通常存放在硬體的 firmware 中,目的是用來載入 & 啟動 OS kernel。

為了做到上述工作,bootstrap 就必須知道 OS 存放的記憶體位址,才有辦法順利載入執行,而 OS 載入後所執行的第一個 process,一般稱為「init」,並等待其他軟/硬體觸發事件以進行處理。

硬體是透過傳遞訊號給 CPU 來觸發 interrupt,而軟體則是透過呼叫 system call 來觸發 interrupt;當 CPU 收到 interrupt 訊號,會執行以下動作:
  1. 立即停止目前工作

  2. 將所要執行的工作傳到特定的位址執行(此位址即為提供執行工作服務的起始位址)

  3. 當工作執行完畢,CPU 則會恢復中斷前的運作

下圖展示出 CPU 執行與工作執行的時間軸:

Interrupt(中斷) 在電腦架構中是非常重要的一個環節,也許不同的電腦會有不同處理 interrupt 的機制,但總是會有共同的部分,當 CPU 收到 interrupt 的訊號時,就會暫停手邊工作,並將 interrupt 丟給合適的中斷處理程序進行處理。

最直接的實作方式是有一個專門的程序(routine),會針對收到的 interrupt 訊號資訊,將其丟給相對應的中斷處理程序處理。

另外一種不需要專門程序處理中斷的方式,則是有一個存放「指向 interrupt routines 的指標(pointer)的表格」,因此 interrupt routine 可以直接透過此 table 儲存的 pointer 進行呼叫,而不需要有個專門的代理程序來處理這個部分。

每個不同設備所產生的 interrupt 都會有不同的 interrupt routine 來處理,並會以唯一的設備編號作為索引,而這些資訊都會儲存在記憶體最前面的位址。


Storage Structure

主記憶體是 CPU 唯一可以直接存取的區域,而兩者之間的互動是透過 CPU 呼叫 store & load 兩個指令,將資料在 memory & register(暫存區)。

其中 load 的作用是將長度為 1 個 word 的資料從 memory 搬到 register 中;而 store 則是將 1 個 word 的資料從 register 回存到 memory 中。

然而,除了基本資料的搬移外,CPU 也是會從 memory 中載入指令以執行不同的工作,其運作步驟如下:
  1. CPU 從 memory 中取得所要執行的指令,並將其存放於 instruction register

  2. CPU 會將此指令拆解成相對應的 CPU 指令集並執行

  3. 最後將執行結果回存至 memory 中

然而,記憶體中的資料是沒辦法永久儲存的,只要停止供電後就會消失;因此需要其他儲存媒體來協助進行資料的儲存,最常見的當然就是硬碟機 or 光碟片了! 當然還有最近很夯的 USB 隨身碟(屬於 flash memory)。


I/O Structure


OS 中有一大部分是專門處理 I/O 的,原因是因為 I/O 的處理好壞會影響到整體系統的效能 & 穩定度。

I/O 動作再 OS 是按照以下步驟進行的:
  1. device driver 會先讀取在 device control 中 register 的資訊

  2. 接著 device controller 會檢視 register 中的內容,判斷所要執行的動作為何 (例如:從鍵盤讀取一個字元)

  3. device controller 開始從裝置中讀取資料至本地端的緩衝區

  4. 資料傳輸完畢,device controller 會發送 interrupt 告知 device driver

  5. 最後 device driver 會將控制權歸還給 OS

  6. 若是執行的動作為 read,就會傳取得的資料(or 指向資料所在的位置的 pointer);但若執行的是其他動作,則會回傳狀態資訊

看了上面的動作,若是還搞不懂,可以將整個動作想像成:設備要傳遞資料到記憶體中,必須一直發中斷給 CPU,並將資料傳給 CPU 後,由 CPU 把資料放入記憶體中。

顯而易見的,所有資料在傳遞時都必須依賴 CPU 的處理,若是速度很慢的裝置(例如:軟碟機)進行 I/O,就會拖垮整個系統的運作效能。

因此,以上的 I/O 動作在處理量少的資料時還可以,但若是處理量大的資料(例如進行 Disk I/O),就會產生極高的 overhead,而為了解決此問題,就有了 DMA(Direct Memory Access) 的產生,以下有張示意圖:


有了 DMA 之後,device 就可以直接將資料以 block 的方式從本身的緩衝區傳入 memory 中,且不會中斷 CPU 的工作,頂多就是當每個 block 資料傳遞完畢後,發個 interrupt 通知 device driver 動作已經完成。

有些更高階的 OS,使用的是 switch 的機制而非 bus 的架構,在這種 OS 中,不同的元件之間不需要在共用的 bus 上搶奪 cycle,且可以同時相互溝通。


參考資料