1

Я ищу несколько раз для записи в файлы (100k +), и записи будут происходить по разветвленной сети. Таким образом, чтобы сделать это, я рассматриваю с помощью Java ExecutorService, чтобы помочь генерировать потоки, но я не совсем уверен, какая комбинация настроек будет правильно сделать следующее произойдет:Правильный способ обработки записи файлов в отдельных потоках

  1. только позволяют 1 запись произойдет в то время, (вопросы заказа, разумеется)
  2. Разрешите писать достаточно времени для проведения каждой записи (скажем, 5 секунд), в какой момент просто залог
  3. Если запись идет медленно, Исполнитель должен собрать записи в очереди и подождать.
  4. Не разрешайте общей программе выйти до тех пор, пока очередь потоков не будет пуста.
  5. Отделите темы писателями. I.e., если в эту функцию входит тот же самый точный автор, поместите его в свою очередь. Если появляется другой указатель писателя, укажите его собственную очередь (нет необходимости помещать отдельных писателей в одну очередь).

Я считаю, что это может быть сделано с комбинацией исполнителя особенности вместе с командой .wait() и .notify() на объекте главной программы. Тем не менее, я просто не уверен, как точно работать с API-интерфейсом исполнителя, чтобы это сделать.

Вот что я получил:

private void writeToFileInSeperateThread(final PrintWriter writer, final String text) { 
    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    try { 
    executor.submit(new Thread(new Runnable() { 
     public void run() { 
     writer.println(text); 
     } 
    })).get(5L, TimeUnit.SECONDS); 
    } catch (Exception e) { 
    e.printStackTrace(); 
    } 
    executor.shutdown(); 
} 

Этот метод будет вызван 100k + раз в течение одного процесса, так что я не уверен, если я должен создать новую ExcutorService экземпляру каждый раз, или используют тот самый? (В моих попытках использовать тот же один, я постоянно получаю исключения, которые я считаю, были связаны с .newSingleThreadExecutor() директивы.

хотел бы остаться Java 5 уступчивый, но Java 6 хорошо. Работает на Windows XP/7.

Update: Это, кажется, сделал трюк в первоначальном тестировании:

private class WriterStringPair { 
    public final PrintWriter writer; 
    public final String text; 

    public WriterStringPair(PrintWriter writer, String text) { 
     this.writer = writer; 
     this.text = text; 
    } 
    } 

    private void writeTextInSeperateThread(Writer writer, String text) { 
    try { 
     textQueue.offer(new WriterStringPair(writer, text), 300L, TimeUnit.SECONDS); 
    } catch (InterruptedException e) { 
     errOut.println(e); 
     e.printStackTrace(); 
    } 
    } 

    final BlockingQueue<WriterStringPair> textQueue = new ArrayBlockingQueue<WriterStringPair>(500); 

    private void setWritingThread() { 
    new Thread((new Runnable() { 
     public void run() { 
     WriterStringPair q; 
     while (!shutdown && !Thread.currentThread().isInterrupted()) { 
      try { 
      q = textQueue.poll(1L, TimeUnit.SECONDS); 
      if (q != null) { 
       q.writer.write(q.text + "\n"); 
       q.writer.flush(); 
      } 
      } catch (Exception e) { 
      e.printStackTrace(); 
      } 
     } 
     } 
    })).start(); 
    } 
+0

Вы говорите, что файл пишет по сети. Вы говорите о NFS или что-то в этом роде? Вы можете рассмотреть возможность использования sftp или более лучших протоколов, которые могут улучшиться по сравнению с «flaky» сетью. – Gray

+0

NFS - это то, что я застрял с ... –

ответ

3

Не зная более подробную информацию о ваших написании файлов по «слоеной» сети и то, что средства, это трудно для нас, чтобы дать конкретику. Но вот о чем подумать.

Я бы выяснил, какое количество одновременных авторов дает вам лучшую производительность здесь - или самый надежный вывод в пункте назначения. Затем вы должны запустить фиксированное количество этих авторов, каждый из которых будет потреблять из общего BlockingQueue (или одну очередь для каждого автора, если это имеет значение). Вы должны быстро превысить свою IO или полосу пропускания сети, начиная с 5 или около того, чтобы записи работали и работали вверх или вниз по мере необходимости.

public void run() { 
    writer.println(text); 
} 

Да, вы не хотите делать подобные вещи с точки зрения работы на линию. Лучше было бы поместить String text в BlockingQueue<String>, а затем у вашего писателя Runnable классов, запущенных в ExecutorService, выходить из очереди и останавливаться только тогда, когда очередь пуста или установлена ​​shutdown boolean.

Как упоминает Питер, вам нужно быть осторожным в заполнении памяти вашими строками в очереди. Если входной текст большой, вы должны установить лимит на BlockingQueue на пару сотен или около того.

Я не уверен, должен ли я создавать новый экземпляр ExecutorService каждый раз или использовать тот же самый?

Конечно, вы должны иметь одну службу и не создать один снова и снова.

Я считаю, что это можно сделать с помощью комбинации функций исполнителя вместе с .wait() и .notify() на объекте главной программы.

Вам не нужно использовать wait и уведомлять, если вы правильно это напишете. У меня будет volatile boolean shutdown = false, который все ваши писатели смотрят. Каждый из них выгружается из текстовой очереди, глядя на остановку. Что-то вроде:

while (!shutdown && !Thread.currentThread().isInterrupgted()) { 
    String text = textQueue.poll(1, TimeUnit.SECONDS); 
    if (text != null) { 
     // write the text 
    } 
} 

Если ошибка записи или что-то, вы можете просто повторить ее или что-то еще, что необходимо.

+0

А это интересная идея. Добавьте писателей и тексты в блокирующий разряд, который выполняет свою задачу в своей собственной теме. Я посмотрю на это! –

+0

Итак, авторы будут в «ExecutorService» @EricS, и тексты будут в разделяемом «BlockingQueue». FYI. – Gray

+0

Что такое хороший предел размера BlockingQueue? Я помещаю в 500. Но будет ли INT_MAX в порядке? (Также я отказался от использования сервера Executor и выбрал простой Thread - я предполагаю, что все в порядке). –

2

Несколько вопросов

  • Println не говорят вам, если там был IOException, поэтому если вы хотите некоторую защиту от ошибок, это не поможет.
  • , начинающийся с ExecutorService для каждой строки, очень медленный, гораздо медленнее, чем отправка задач.
  • Создание множества задач будет не только очень медленным, но и может использовать всю вашу память, если это так.
  • вы отправляете Runnable, а не потоки в ExecutorService
  • shutdown не останавливает поток, если, например, он блокирует запись. Это может привести к тому, что многие нити останутся лежащими вокруг, пытаясь написать все в одно и то же время.

Я предлагаю хранить данные в локальной системе, например JMS или базе данных или файлах (например, Java-Chronicle), и иметь отдельный процесс, копируя данные в NFS, когда он доступен.

Это предполагается, что вы не можете исправить NFS, чтобы он не был шелушащимся.

+1

Хмм, поэтому println не будет вызывать IOExceptions, даже если есть ошибка ввода-вывода диска? –

+1

@EricS Он никогда не выбрасывает исключения. –

+0

Спасибо, я переключился на .write (text + "\ n") сейчас. –