Несколько потоков, извлекающих текст из iText PDF
Я пытался ускорить извлечение текста из файлов PDF. Я пробовал SnowTide's PDFTextStream
, Это было медленнее, чем iText на моем компьютере.
Моя последняя попытка - использовать несколько потоков.
Я инициализирую PdfReader
с байтовым массивом вместо имени файла. Это сделано для того, чтобы я мог избежать задержки ввода-вывода, запустив все это в память. Из того, что я могу сказать, iText получает данные из файла по мере необходимости. С байтовым массивом такой проблемы быть не должно.
Я использую потоки, чтобы извлечь несколько диапазонов страниц.
Тем не менее, это сделало это намного медленнее. Использование одного потока против пяти быстрее. Я не знаю, почему это так. Из того, что я могу сказать, "бутылочное горлышко" извлекает саму страницу PdfTextExtractor.getTextFromPage(mReader, i)
, Я рассчитал цикл for, который объединяет текст потока и не влияет на общее время.
Мой вопрос: почему это медленнее и как я могу сделать это быстрее?
Доступ к тому же PdfReader
создавая узкое место? Должен ли я инициализировать несколько PdfReader
с тем же байтовым массивом? Я ошибаюсь в каком-либо из моих исследований? Если у кого-то есть предложения по поводу совершенно новых открытых экстракторов PDF или другие предложения, это было бы здорово!
import java.io.*;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import com.itextpdf.text.pdf.PdfReader;
import java.nio.channels.FileChannel;
import java.nio.MappedByteBuffer;
public class PDFParser
{
private PdfReader mReader;
private int numPages;
private String bodyText;
public PDFParser(String pdf)
throws IOException
{
/*
scrapped this
mReader = new PdfReader(pdf);
and replaced with the following.
From what I can tell Pdfreader with the above constructor
probably uses a stream to get the pages one at a time.
I want to load it all into memory to increase the speed.
*/
final FileChannel channel = new FileInputStream(pdf).getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
byte[] byteArray = new byte[buffer.remaining()];
buffer.get(byteArray);
channel.close();
mReader = new PdfReader(byteArray);
numPages = mReader.getNumberOfPages();
bodyText = "";
}
public String parse()
{
int numThreads = 5;
int offset = (numPages / numThreads) - 1;
int currentFirstPage = 1;
ParserThread[] threads = new ParserThread[numThreads];
int forEnd = numThreads - 1;
for (int i = 0; i < forEnd; i++)
{
threads[i] = new ParserThread(mReader, currentFirstPage, currentFirstPage + offset);
threads[i].start();
currentFirstPage += offset + 1;
}
threads[forEnd] = new ParserThread(mReader, currentFirstPage, numPages);
threads[forEnd].start();
try
{
long before = System.currentTimeMillis();
for(int i = 0; i < numThreads; i++)
threads[i].join();
System.out.println(System.currentTimeMillis() - before);
}
catch(InterruptedException ie){ie.printStackTrace();}
mReader.close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numThreads;i++)
{
sb.append(threads[i].getText());
}
bodyText = sb.toString();
if (bodyText != "")
return bodyText;
else
return "error";
}
public static void main(final String args[]) throws IOException
{
for (int i = 0; i < args.length; i++)
{
String text = new PDFParser(args[i]).parse();
// System.out.println(text);
}
}
}
class ParserThread extends Thread
{
private PdfReader mReader;
private int mFirstPage;
private int mLastPage;
private String text;
ParserThread(PdfReader reader, int firstPage, int lastPage)
{
mReader = reader;
mFirstPage = firstPage;
mLastPage = lastPage;
text = "";
}
@Override
public void run()
{
StringBuilder sb = new StringBuilder();
try
{
for (int i = mFirstPage; i <= mLastPage; i++)
sb.append(PdfTextExtractor.getTextFromPage(mReader, i));
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
text = sb.toString();
}
public String getText()
{
return text;
}
}