2

我认为这是一个有趣的编程问题,所以我发布了它,即使我认为我有一个足够好的解决方案想法,请参阅 (*)。如果有人有一个优雅的解决方案,我很乐意看到它!

我正在使用一种调用外部库的方法,该库向服务器发出 http 请求。我需要有 K 个字符串作为输入才能有效,即外部资源的每次调用都是一个 HTTP 请求,我需要缓冲一些数据以提高效率。(例如,让 K 为 200,并在文本中以 1% 的概率作为标记出现,因此在找到 200 个输入参数之前,我需要处理 20,000 个标记)。

实际上,它的作用是:externalHTTP(commaDelimitedString) -> 获取有关每个字符串的信息。示例 externalHTTP("foo,bar") -> ["信息片段 1","信息片段 2"]。其中“信息片段 1”是关于“foo”的。

我想用信息片段替换长文本(字符串)中的“foo”和“bar”,但前提是我的 HTTP 请求缓冲区已满。在等待这种情况发生时,我仍然想继续阅读原始字符串。

文本通过拆分进行标记(因此我正在使用字符串数组)。

即我不想仅仅因为我正在等待 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 不同(只有一点点不同)。

4

1 回答 1

1

好的...这是尝试使用示例代码完全回答您的问题。

我从来没有经常玩线程,所以我想我今晚会尝试学习一些东西。

此解决方案使用线程来允许异步发生 http 请求。

使用Thread.sleep()模拟异步请求。

我的测试用例很原始:主类只休眠 30 秒以等待一切完成。

就像我说的,我是线程编程的新手,所以我可能忽略了一些东西。

希望这能让你朝着正确的方向开始......

/**
 *  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());
    }

}
于 2012-09-03T09:24:18.480 回答