2

これは興味深いプログラミングの問題だと思ったので、十分に優れた解決策のアイデアがあると思いますが、投稿しました (*) を参照してください。誰かがエレガントなソリューションを持っているなら、私はそれを見たいです!

サーバーへの http 要求を行う外部ライブラリを呼び出すメソッドを使用しています。有効にするには、入力として K 個の文字列が必要です。つまり、外部リソースの各呼び出しは HTTP リクエストであり、有効にするために一部のデータをバッファリングする必要があります。(例として、K を 200 とし、1% の確率でテキスト内のトークンとして発生するため、200 個の入力引数を見つける前に 20,000 個のトークンを処理する必要があります)。

これが実際に行うことは次のとおりです: externalHTTP(commaDelimitedString) -> 各文字列に関する情報を取得します。例 externalHTTP("foo,bar") -> ["情報スニペット 1","情報スニペット 2"]. 「情報スニペット 1」は「foo」に関するものです。

長いテキスト (文字列) の "foo" と "bar" を情報スニペットに置き換えたいのですが、HTTP 要求のバッファがいっぱいになった後でのみです。これが起こるのを待っている間、私はまだ元の文字列を読み続けたい.

テキストは分割によってトークン化されます (そのため、文字列の配列を操作しています)。

つまり、K 個の文字列がバッファリングされるのを待っているという理由だけで、テキスト処理の実行を停止したくありません。

最初は、後で更新する個々の文字列オブジェクトとして単語を保存できると思っていましたが、文字列は不変であるため、値によって呼び出されることに気付きました。

(*) 私の 2 番目のアイデアは、単語 (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;
            } 
        } 
    }

}

さらに複雑なのは、いくつかの長いテキストを処理したいので、テキストごとに 1 つの文字列配列のマトリックスが必要になることです。

クラス既知の参照が好きではない

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 に答える