Я написал следующий код Java:
twitterStream.addListener(new StreamListener());
FilterQuery filterQuery = new FilterQuery();
filterQuery.follow(filteringUsers);
filterQuery.track(filteringWords);
twitterStream.filter(filterQuery);
для отслеживания некоторых пользователей и ключевых слов в Twitter (через Streaming API). Здесь StreamListener
- это моя личная реализация слушателя.
Я отслеживаю множество ключевых слов, хэштегов и пользователей, и поэтому я накапливаю в памяти много твитов, ожидающих обработки. Фактически, я просто беру их через слушателя (в onStatus()
) и смывая их в базе данных.
Тем не менее, факт, что они должны ждать в памяти, очевидно, насыщает память через несколько часов. За 20 минут я заработал в памяти 177000 LinkedBlockingQueue$Node
и 1.272MB char[]
(просматривается через профилирование).
Я бы хотел, чтобы конвейер работал непрерывно, и, очевидно, это невозможно в текущем состоянии.
Таким образом, я хотел бы знать, есть ли способ добавить несколько слушателей в многопоточность, чтобы они могли одновременно опустошать очередь твитов и ускорить обработку.
Заранее спасибо.
Хотя прямое многопоточное решение невозможно через Twitter4J, можно было бы решить имитировать обработку многопоточных запросов через класс слушателя.
Предположим, StreamListener
- это ваша специализация слушателя StatusListener
Twitter4J.
Мы копируем очередь внутри StreamListener
как частный атрибут:
private LinkedBlockingQueue<String> tweets;
Очередь инициализируется в конструкторе:
tweets = new LinkedBlockingQueue<String>();
Более того, в конструкторе мы создаем пул потоков, предназначенный для чтения твитов из очереди (в партиях) и хранения их в базе данных:
final ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
Runnable tweetAnalyzer = defineMonitoringRunnable(tweetRepository);
for (int i = 0; i < NUM_THREADS; i++) {
executor.execute(tweetAnalyzer);
try {
Thread.sleep(THREADS_DELAY);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
где объект Runnable
может быть построен следующим образом:
private Runnable defineMonitoringRunnable(final TweetRepository tweetRepository) {
return new Runnable() {
@Override
public void run() {
List<String> tempTweets = new ArrayList<String>();
while (true) {
if (tweets.size() > 0) {
tempTweets.clear();
tweets.drainTo(tempTweets);
tweetRepository.insert(tempTweets);
}
try {
Thread.sleep(TWEETS_SAVING_TIME);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
};
}
(TWEETS_SAVING_TIME
- время ожидания каждого объекта Thread
между одним сохранением твита и другим)
Наконец, метод onStatus()
сохраняет твиты в очереди, как только они приходят к слушателю:
@Override
public void onStatus(Status status) {
tweets.add(TwitterObjectFactory.getRawJSON(status));
}