google-code-prettify

顯示具有 IT 標籤的文章。 顯示所有文章
顯示具有 IT 標籤的文章。 顯示所有文章

2015年1月23日 星期五

簡易限制同時多執行緒數量Simple Limited Concurrent Multi-thread

因為工作常需要處理較大數量的資料,
使用單執行緒耗時較久,
所以就想寫一個多執行緒的程序來做,
但不能無限制的往Server丟,
Server恐怕也會吃不消,
所以必須控制同時多執行緒執行的數量。
另外,也為了要考量到原本已寫好的Service必須可以直接使用,
套用多執行緒後不用改Code,
保持需要時,原本只有主執行緒運算的狀況下仍可進行,
所以就利用時間寫了以下這樣一個簡易可以指定同時間多執行緒數量的程式,
並且這個控制同時執行緒數量的框架架構可以在後來其他新的程式工作直接套用即可,
不需再寫產生多執行緒、控制Concurrent Multi-thread的程式。
 

public interface BatchService {
 public Collection<!----> retrieveSource() throws Exception;
 public void doJob( Object obj ) throws Exception;
}


 
public interface Job extends Runnable {
 public void setData(Object obj);
 public void setService(BatchService service);
}

 
public class JobImpl implements Job {

 //private static Logger log = Logger.getLogger(JobImpl.class);
 
 private Object data;
 private BatchService service;
 
 @Override
 public void run() {
  Thread.currentThread().setName(Thread.currentThread().getId()+"");
  if (data == null || service == null) return;
  
  try {
   service.doJob(data);
   this.setData(null);
   this.setService(null);
   
   
  } catch (Exception e) {
   e.printStackTrace();
   //System.out.println(e.getMessage());
   //log.error(e.getMessage());
   
  }finally{
   BatchInit.infoJobFinishCount(this);
  }
 }

 @Override
 public void setData(Object obj) {
  data = obj;
  
 }

 @Override
 public void setService(BatchService service) {
  this.service = service;
 }

}

 

public class BatchInit {
 //private static Logger log = LogManager.getLogger("BatchInit");
 public static Stack<job> jobStack;

 private static int JobFinishCount = 0;

 
 public void batchJob(BatchService batchService, Stack<job> jobs) throws Exception{
  List<!----> source = (List<!---->)batchService.retrieveSource() ;
  int JobAmount = source.size();
  jobStack = jobs;
  int JobNow = 0;
  //log.info("JobAmount::"+JobAmount);
  
  while(true){
   if (JobAmount==JobFinishCount){
    //System.out.println("做完了::"+JobFinishCount);
    //log.info("做完了::"+JobFinishCount);
    break;
   }
   Job job = null;
   try{
    job = jobStack.pop();
    
   }catch(java.util.EmptyStackException ex){
  
   }catch(Exception ex){
    ex.printStackTrace();
    //log.error(ex.getMessage());
   }
   
   //log.debug("#######job ::"+job);
   if (job != null && JobNow < JobAmount ){
    loga(JobFinishCount, "");
    Object obj = source.get(JobNow);
    ++JobNow;
    job.setData(obj);
    job.setService(batchService);
    Thread t = new Thread(job, job.toString());
    t.start();
    
   }
   
  }
  
 }

 public synchronized static void infoJobFinishCount( Job job){
  ++JobFinishCount;
  jobStack.push(job);
  
 }
 
 private void loga(int i, String message){
  if (i % 500 == 0){
   System.out.println("--doing :" +i+", "+message);
   //log.info("--doing :" +i+", "+message);

  }
 }
}


上面的程式是控制同一時間執行緒的最大數量,之後不用在改(除非有Bug,或為了提升效率),
以後新的需要多執行緒進行的程式可以直接引用。
而下面的兩隻程式必須要寫,
一個是實作每一個Batch Job Service的實際工作必須implements BatchService這個interface,
另一個則是啟動程式和同一時間處理Job數量(執行緒數量)設定
 

public class MyBatchJobService implements BatchService {

 @Override
 public Collection<!----> retrieveSource() throws Exception {
  //TODO write your code
  ArrayList<String> source = new ArrayList<String>();
  source.add("Hello ");
  source.add("Ryan! ");
  source.add("How ");
  source.add("are ");
  source.add("you? ");
  
  for(int i = 0 ; i < 10 ; i++){
   source.add(""+i);
  }
  return source;
 }

 @Override
 public void doJob(Object obj) throws Exception {
  //TODO write your code 
  String data = (String) obj;
  System.out.println("ThreadId:"+ Thread.currentThread().getId() +"::"+data);
 }

}


執行BatchStart啟動程式。
 
public class BatchStart {

 private static BatchInit batchInit = new BatchInit();
 
 public static void main(String[] args) throws Exception {
  BatchService service = new MyBatchJobService();
  batchJob(service, 2);
  
 }

 private static void batchJob(BatchService service, int amountThread)
   throws Exception {
  Stack jobs = new Stack();
  
  for(int i =0; i < amountThread; i++){  //TODO Setting the amount of concurrent thread
   jobs.push(new JobImpl());
   
  }
  
  batchInit.batchJob(service, jobs);
 }
}

開放原始碼下載:GitHub

2015年1月17日 星期六

Maven設定Proxy

到一個新環境,拿到一個新Project source,
 一打開Project冒出下面這樣的錯誤:
ArtifactDescriptorException: Failed to read artifact descriptor for ......
Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-resources-plugin:jar:2.6

接著看到pom.xml冒出一堆錯誤...,
有可能是所處的網路環境會經過Proxy Server,
所以可以試著給Maven設定Proxy可以解決這樣的問題。

編寫一個settings.xml格式如下:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
 http://maven.apache.org/xsd/settings-1.0.0.xsd">
 <localRepository/>
 <interactiveMode/>
 <usePluginRegistry/>
 <offline/>
 <pluginGroups/>
 <servers/>
 <mirrors/>
 <proxies>
  <proxy>
   <id>myproxy</id>
   <active>true</active>
   <protocol>http</protocol>
   <host>your proxy server address</host>
   <port>your proxy server port</port>
   <username>your proxy account</username>
   <password>your proxy password</password>
   <nonProxyHosts>localhost,127.0.0.1</nonProxyHosts>
  </proxy>
 </proxies>
 <profiles/>
 <activeProfiles/>
</settings>

以Eclipse來說,到以下的選單:
Window > Preferences > Maven > User Settings
在這個畫面指定上面的settings.xml

2015年1月9日 星期五

Java在cmd環境下執行的編碼問題

編寫了call Web-service的client程式,
將資料組成JSON的格式送至Server,
在Eclipse下執行一切相安無事,
但是在cmd的環境執行時,
卻有些資料會收到Server回傳400錯誤。

將有問題的JSON資料在cmd畫面中印出來放到jsonlint驗證, 卻是一切正確。 
仔細看了發生錯誤的幾筆資料,
發現資料內容都有含一些特殊符號(例如:數學符號),
所以應該就是編碼的問題。
因為在Eclipse中編寫java時,
整個環境都是設定為UTF-8編碼,
而cmd的環境卻是Big5編碼。 

解決的方式:
1. 在執行java時,給予「-Dfile.encoding=UTF-8」參數。這樣可以解決資料處理時的編碼問題。
2. 在cmd下執行「chcp 65001」指令,65001是表示設定為UTF-8(Big5為950),並到以下的畫面設定字型。這樣可以解決cmd印出中文出現亂碼的問題。


以上的作法可以編寫成以下這樣一個.bat檔,
這樣執行程式時,就方便很多了。
chcp 65001
java -Dfile.encoding=UTF-8 你的java程式 

2015年1月8日 星期四

MongoDB使用forEach進行非固定值update

使用關聯式資料庫時,
如果只是想要簡單的以該筆資料的A欄位狀況來update它的B欄位值,
可以很簡單的用類似以下的SQL進行:
update tableA set column_B = column_A+"-new value" 
where column_C="abc";

在MongoDB中我並沒有發現有像SQL這麼簡單程式碼就可以達到相同的作法, 所以使用forEach的方式來達到同樣的目的:
db.tableA.find({"column_C":"abc"}).forEach( 
    function(myDoc) { 
        if (myDoc.column_A == null){
            return;
        }

        db.tableA.update({"column_PK":myDoc.column_PK},{ "$set": { "column_B": myDoc.column_A+"-new value"}});

    } 
);  

2014年9月6日 星期六

D3 JavaScript Framework Demo

藉由研讀「網頁互動式資料視覺化:使用 D3 (Interactive Data Visualization for the Web)」這本書,
學習D3這套JavaScript Framework,
雖然書本有附上原作者的範例程式,
但一昧的照著範例程式打字實在無聊,
所以就盡量作一些變化,
例如:採用自己準備的資料、將原作者多支範例程式進行整合、使用台灣地圖資料等等。
過程中也不免需要去找一些作者沒提到或沒示範的處理方式來自我練習呈現在我的程式之中,
相對的收穫也較大。
我將這部份的程式放在GitHub作為分享,
提供需要的人作為參考!

Demo:http://pintse.github.io/D3Demo/

Source Code:https://github.com/pintse/D3Demo

我所使用的台灣地圖GeoJSON資料要感謝g0v熱血提供。

2013年2月23日 星期六

Git Server (Win 7 64bit) 安裝SSH

1.在os系統變數的「Path」變數中,加入Git安裝路徑下的bin和libexec\git-core兩個目錄,ex:C:\Git\bin 和 C:\Git\libexec\git-core




2.安裝Copssh(網址:https://www.itefix.no/i2/copssh ),我使用預設帳號「SvcCOPSSH」,這會在OS建立一個「SvcCOPSSH」帳號。



3. 安裝過程中,會跳出訊息,告訴你可能安裝完成後,要使用他的「Activate a user」工具,讓自己指定的帳號可以使用SSH連線



4. 在「Activate a user」工具指定OS已經存在的帳號來使用SSH的連線,其他設定我使用預設值,按Next之後,過程中會要輸入Passphrase



如果打了一個os沒有設定的帳號,會出現錯誤訊息,看起來這套軟體的帳號是和os的使用者帳號綁在一起的。



5. 「Activate a user」完成後,在Copssh的安裝目錄下的home目錄裡會新增以剛剛指定的帳號名稱為目錄名的使用者目錄,並且在裡面有自動產生的Public key和 Private key,要把Private Key給Client端那位使用者



6.在Client端使用TortoiseGit安裝進來的「Puttygen (PuTTY  Key Generator)」工具,點選「Load」,將前一步驟Server產生的Private Key (ex: ryanchen.key)選入,隨後跳出Enter Passphrase for key視窗,輸入在Server端使用「Activate a user」指定帳號的過程中輸入的Passphrase 。



6.1 最後按「Save private key」儲存server端給的Private key專換成Putty運行的Private key。




7.設定防火牆,開SSH的連接埠(Port),從控制台的防火牆畫面點擊「進階設定」,開啟以下視窗,點「輸入規則」之後到右邊點「新增規則」,規則類型選「連接埠」,套用到TCP、特定本機連接埠指定「22」,這是SSH預設的port,之後照著點下一步,完成設定。




8. 測試過如果Repository是在C槽,使用SSH連線都可以正常Clone,但是在D槽就不行了,試了使用「03. Start a Unix BASH Shell」工具在Copssh安裝路徑下(C:\Program Files (x86)\ICW)建立D槽Repos的上兩層目錄的symbolic link,還是無法連到Repos,還不知道要改那裏的設定才可以連D槽的Repos,會的高手教一下吧!

9. SSH連進來C槽就是「/」目錄,如果「C:\TestRepos」,SSH連線URL為「ssh://你的帳號@Server位址/TestRepos」

10. ssh帳號與os帳號綁在一起。要用的帳號必須在os建立帳號。


困惑點:
使用Copssh的「03. Start a Unix BASH Shell」工具或是Putty走ssh登入後,「/」路徑實際為Copssh安裝的目錄,但是使用TortoiseGit走ssh的url設為「ssh://ryanchen@Server位址/TestRepos」,TestRepos實際目錄在Windows的 C:\ 下,而不是在「Copssh」的安裝目錄下,我並沒有特別設定TestRepos,不知道為何Copssh和TortoiseGit的「/」為什麼會不一樣?如果能弄清原因,也許就知道為什麼讀不到D槽了。

2013年2月22日 星期五

Git筆記(單機安裝)

以下環境在同一台win 7 64bit上


1. Git是軟體系統,而Github是一個公司提供Git server服務,一般使用者可以用Github的服務當做自己的git server,如果程式是open source,讀取權限是Public,就免費,否則要收費。

2. Git軟體我從這個網址下載: http://git-scm.com/ 

3. Git的GUI Client端軟體我選擇安裝 tortoisegit , 網址:http://code.google.com/p/tortoisegit/

4.使用Visual studio 2010 搭配Git,我選擇安裝Git Source Control Provider 。安裝步驟:
4.1到擴充管理員

4.2 到「線上圖庫」右邊搜尋欄輸入「git」,找到「Git Source Control Provider」點選他進行下載安裝,安裝軟體玩,需要點選重新啟動Visual Studio 。


4.3重開VS之後,到「選項」

4.4 目前的原始碼控制外掛程式選擇「Git Source Control Provider」


5. Git的Server與Client的Repository之間的架構關係如下圖,下圖作者為ihower,
取材網址: http://www.slideshare.net/ihower/git-tutorial-13695342?ref=http://ihower.tw/blog/archives/6696/


6.在要當Server的機器上,使用Git Bash工具,開啟後,切換到要做Repository的目錄,執行以下指令:
$git init --bare Repository的名字

上面使用「--bare」參數,表示這是個純粹的Repository,不放工作副本Working copy,也就是Server端的Repository,看不到原本被控管的檔案實際樣貌,只看到Git創建的檔案。

7.在client端使用TortoiseGit,在要當Client端Repository的目錄上,按右鍵選擇「Git Clone」 ,跳出下面的視窗,URL輸入server端的Repository路徑,因為目前練習Server與client在同一台機器,所以直接輸入檔案路徑,按確定,之後會在目錄裡產生「.git」目錄。可以在Client端Repository這個目錄裡開始新增檔案。我是把「.git」目錄移到我原本的程式專案目錄裡。


8.因為我把拉下來的「.git」移到我原本的程式專案目錄,打開Visual studio後,就會在「方案總管」看到裡面檔案的圖示不一樣了,例如:當檔案與Repository裡的一樣時,會顯示「鎖」的圖示,如果有修改過與Repository不一致時,會顯示「紅色勾勾」的圖示。在這裡的檔案上面按右鍵就可以直接做Git的控管


9. 因為「Git Source Control Provider」會使用使用者需事先安裝的Git GUI Client軟體,所以我設定他使用TortoiseGit,因此Git Source Control Provider執行Git動作時,會呼叫TortoiseGit或Git對應的介面或工具,讓使用者操作。

10.在方案root上做Commt動作,把所有未列管而想列管的都Commit進去Repository,這樣開始就有第一版的控管檔案。

11.在其他Client端,做「Git Clone」後,也就新建出本地端的Working Copy。

12. Server在遠端,Client與Server之間使用SSH連線,請見