2012-09-03 9 views
2

我認爲這是一個有趣的編程問題,所以我發佈了它,即使我認爲我有一個足夠好的解決方案的想法,請參閱(*)。如果有人有一個優雅的解決方案,我很想看到它!如何異步修改字符串數組

我正在調用一個方法,該方法調用向服務器發送http請求的外部庫。我需要有K個字符串作爲輸入才能生效,即每次調用外部資源都是一個HTTP請求,我需要緩衝一些數據以提高效率。 (例如,假設K是200,並且在文本中出現的概率爲1%,所以我需要在查找200個輸入參數之前處理20,000個令牌)。

有效地這樣做是:externalHTTP(commaDelimitedString) - >獲取有關每個字符串信息。示例externalHTTP(「foo,bar」) - > [「信息片段1」,「信息片段2」]。 「信息片段1」是關於「富」的地方。

我要替換一個長文本(字符串)與信息片段,但只有在我的HTTP請求緩衝區已滿的「富」與「酒吧」。我仍然希望在等待這種情況發生時繼續閱讀原始字符串。

文本通過分割進行標記(所以我正在處理一個字符串數組)。

I.e.我不想停止執行我的文本處理,因爲我正在等待K字符串緩衝。

起初,我以爲我可以存儲單詞作爲單個字符串對象,我以後更新,但後來我意識到,字符串是不可變的,因此是值調用。

(*)第二個想法是存儲的字(foo和bar)指數和然後按順序插入片段回原始字符串數組當HTTP請求結束。像

class doStuff { 

    String text[]; 
    LinkedList<Integer> idxList = new LinkedList<Integer>(); 

    public doStuff(String[] t) { 

     text = t; 
     int i = 0; 
     for (String token : text) { 
      if (shouldReplaceToken(token)) { 
       replaceToken(i); 
      } 
      i++; 
      //do other work with the tokens 
     } 
    } 


    void replaceToken(int i) { 

     idxList.add(i); 
     if (++count > buffSize) { 
      count = 0; 
      String commaDelim = ""; 
      ListIterator<Integer> it = idxList.getListIterator(0); 
      while (it.hasNext()) { 
       commaDelim += text[it.next()]+","; 
      }  
      String[] http_response = http_req(commaDelim); 
      for (String snippet : http_response) { 
       idx = idxList.poll(); //this is not elegant, dependent on FIFO order 
       text[Idx] = snippet; 
      } 
     } 
    } 

} 

使事情更加複雜的是,我要處理一些較長的文本,所以我將不得不需要有字符串數組,每個文字的矩陣。

我不喜歡類已知的參考

String[] text 

或他們的方式我處理這個代碼指數...

希望能看到一些建議:)

編輯:有點變得更清楚了。我真的不能說我正在查找,不透露等,對不起。有些名稱可能與java不同(只有很小的差別)。

+1

你的問題的描述是很難理解。請嘗試編輯問題,以便外部人員更容易遵循。假設我們什麼都不知道,並且對你想要做什麼有清晰的描述。一個具體的例子會很有幫助。 – jahroy

+1

即使是第一句也不可能理解:_I正在調用需要使K字符串作爲輸入的外部資源的方法,即每次調用外部資源都是HTTP請求,並且需要緩衝一些數據有效性._ K字符串是什麼意思? 「緩衝一些數據以提高效率」這句話對解釋你想達到的目標沒有什麼作用。 – jahroy

+0

這基本上是關於在HTTP請求發生時調用特定的子字符串來註冊偵聽器。與異步事件進行比較。 – user1443778

回答

1

好的...這是試圖用示例代碼完全回答你的問題。

我從來沒有玩過太多線程,所以我想我會試着學習一些東西。

該解決方案使用線程來允許http請求異步發生。

異步請求是通過使用Thread.sleep()模擬。

我的測試用例是原始的:主類只是睡覺30秒等待一切都結束了。

就像我說的,我是Thread編程的新手,所以我可能忽略了一些東西。

希望這可以讓你在正確的方向開始......

/** 
* A class that asynchronously replaces text in an 
* array of strings by using helper threads. 
*/ 

public class TextReplacer { 

    private final int bufferSize; 

    List<String> wordList  = new ArrayList<String>(); 
    List<Integer> indexList  = new ArrayList<Integer>(); 
    int   bufferPosition = 0; 
    int   lastPosition = 0; 

    public TextReplacer(String[] a, int n) { 
     bufferSize = n; 
     if (a != null) { 
      wordList = Arrays.asList(a); 
     } 
    } 

    public void replaceText() { 
     int i = 0; 
     for (String thisWord : getWordListCopy()) { 
      if (shouldReplaceToken(thisWord)) { 
       indexList.add(i); 
       processTextReplacement(); 
      } 
      i++; 
     } 
    } 

    private void processTextReplacement() { 
     if (isBufferReady()) { 
      int currentPos = lastPosition; 
      replaceStrings(getCsv(), currentPos); 
     } 
    } 

    /** Uses a thread to replace strings in wordList. */ 

    private void replaceStrings(String csv, int pos) { 
     new ReplacerThread(wordList, indexList, csv, pos, bufferSize).start(); 
    } 

    private String getCsv() { 
     StringBuilder csv = new StringBuilder(); 
     for (int i = 0; i < bufferSize; i ++) { 
      int idx = indexList.get(lastPosition++); 
      csv.append(wordList.get(idx)).append(","); 
     } 
     return csv.toString(); 
    } 

    private boolean isBufferReady() { 
     bufferPosition++; 
     return (bufferPosition % bufferSize == 0); 
    } 

    private List<String> getWordListCopy() { 
     List<String> listCopy = new ArrayList<String>(); 
     listCopy.addAll(wordList); 
     return listCopy; 
    } 

    /** 
    * Simulates a 10% replacement rate by only 
    * returning true for input that ends with a 3. 
    */ 

    private boolean shouldReplaceToken(String s) { 
     return s.endsWith("3"); 
    } 

    public List<String> getWordList() { 
     return wordList; 
    } 

    public String[] getWordArray() { 
     return wordList.toArray(new String[0]); 
    } 

} 


/** 
* A thread that sleeps for up to 8 seconds, then 
* replaces a bunch of words in the list that is 
* passed to it in its constructor. 
*/ 

public class ReplacerThread extends Thread { 

    List<String> originalWords; 
    List<Integer> indices; 
    String wordCsv; 
    String[] replacementWords; 
    int startPos; 
    int bufferSize; 
    int maxSleepMillis = 8000; 
    int sleepMillis = getSleepMillis(); 
    int threadNum;       // for debugging 
    String prefix = new String();   // for debugging 

    /** Create a new thread. */ 

    public ReplacerThread(List<String> o, List<Integer> i, 
          String c, int p, int n) { 
     originalWords = o; 
     indices = i; 
     wordCsv = c; 
     startPos = p; 
     bufferSize = n; 
     threadNum = startPos/bufferSize; 
     int count = 0; 
     while (count++ < threadNum) { 
      prefix += " "; 
     } 
    } 

    @Override 
    public void run() { 
     replacementWords = httpReq(wordCsv); 
     for (int i = 0; i < bufferSize; i ++) { 
      int pos = startPos + i; 
      int idx = indices.get(pos); 
      originalWords.set(idx, replacementWords[i]); 
     } 
     print("Thread #" + threadNum + " COMPLETE"); 
    } 

    /** Simulate an asynchronous http request by using Thread.sleep */ 

    private String[] httpReq(String s) { 
     try { 
      printSleepMessage(); 
      sleep(sleepMillis); 
     } 
     catch (InterruptedException ex) {} 
     String[] repText = s.split(","); 
     for (int i = 0; i < repText.length; i++) { 
      repText[i] = repText[i].replace("Line", "Funky Line"); 
     } 
     return repText; 
    } 

    private void printSleepMessage() { 
     int ms = sleepMillis/1000; 
     print("Thread #" + threadNum + " SLEEP(" + ms + ")"); 
    } 

    private int getSleepMillis() { 
     Double ms = maxSleepMillis * Math.random(); 
     return ms.intValue(); 
    } 

    public void print(Object o) { 
     String s = (o == null ? "null" : o.toString()); 
     System.out.println(prefix + s + "\n"); 
    } 

} 

/** A class that tests my funky solution. */ 

public class Main { 

    static String inputFile = "test-input.txt"; 
    static int bufferSize = 50; 

    public static void main(String[] args) { 
     String[] theInput = readInput(); 
     TextReplacer testItem = new TextReplacer(theInput, bufferSize); 
     testItem.replaceText(); 
     try { 
      // wait 40 seconds for everything to happen 
      Thread.sleep(40000); 
     } 
     catch (InterruptedException ex) { } 
     dumpOutput(testItem.getWordArray()); 
    } 

    public static String[] readInput() { 
     File inFile = new File(inputFile); 
     List<String> lineList = new ArrayList<String>(); 
     try { 
      BufferedReader buff = new BufferedReader(new FileReader(inFile)); 
      String currentLine = buff.readLine(); 
      while (currentLine != null) { 
       lineList.add(currentLine); 
       currentLine = buff.readLine(); 
      } 
     } 
     catch (IOException ignoreMe) {} 
     print("Lines read: " + lineList.size()); 
     return lineList.toArray(new String[0]); 
    } 

    public static void dumpOutput(String[] txt) { 
     long ms = System.currentTimeMillis(); 
     String fileName = "output-" + ms + ".txt"; 
     File outFile = new File(fileName); 
     try { 
      BufferedWriter buff = new BufferedWriter(new FileWriter(outFile)); 
      for (String s : txt) { 
       buff.write(s); 
       buff.newLine(); 
      } 
     } 
     catch (IOException ignoreMe) {} 
     print("Lines written: " + txt.length); 
     print("File:   " + fileName); 
    } 

    public static void print(Object o) { 
     System.out.println(o == null ? "null" : o.toString()); 
    } 

}