Безопасен ли метод Files.write (). [Дубликат]

TL; DR: Попробуйте использовать Html.Partial вместо Renderpage


Я получал Object reference not set to an instance of an object, когда пытался сделать вид в представлении, отправив ему модель, например это:

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

Отладка показала, что модель была Null внутри MyOtherView. Пока я не сменил его на:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

И это сработало.

Кроме того, причина, по которой я не имел Html.Partial для начала, заключалась в том, что Visual Studio иногда выдает ошибки, (f9), если он находится внутри другого построенного цикла foreach, хотя это не ошибка:

@inherits System.Web.Mvc.WebViewPage
@{
    ViewBag.Title = "Entity Index";
    List<MyEntity> MyEntities = new List<MyEntity>();
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
}
<div>
    @{
        foreach(var M in MyEntities)
        {
            // Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
            @Html.Partial("MyOtherView.cshtml");
        }
    }
</div>

Но я смог запустить приложение без проблем с этим " ошибка". Я смог избавиться от ошибки, изменив структуру цикла foreach, чтобы выглядеть так:

@foreach(var M in MyEntities){
    ...
}

Хотя я чувствую, что это потому, что Visual Studio неправильно интерпретировала амперсанды и скобки .

15
задан lucian.pantelimon 2 April 2012 в 09:37
поделиться

6 ответов

Если вам нужно какое-то подобие производительности и простоты управления, перейдите в очередь производителей-потребителей и только один файловый писатель, как это было предложено Алексом и другими. Разрешить все потоки в файле с мьютексом просто беспорядочно - каждая задержка на диск переносится непосредственно в главные функциональные возможности приложения (с дополнительным утверждением). Это особенно непримиримо с медленными сетевыми дисками, которые, как правило, уходят без предупреждения.

2
ответ дан Martin James 27 August 2018 в 15:12
поделиться

Если вы можете сохранить файл в качестве FileOutputStream, вы можете заблокировать его следующим образом:

FileOutputStream file = ...
....
// Thread safe version.
void write(byte[] bytes) {
  try {
    boolean written = false;
    do {
      try {
        // Lock it!
        FileLock lock = file.getChannel().lock();
        try {
          // Write the bytes.
          file.write(bytes);
          written = true;
        } finally {
          // Release the lock.
          lock.release();
        }
      } catch ( OverlappingFileLockException ofle ) {
        try {
          // Wait a bit
          Thread.sleep(0);
        } catch (InterruptedException ex) {
          throw new InterruptedIOException ("Interrupted waiting for a file lock.");
        }
      }
    } while (!written);
  } catch (IOException ex) {
    log.warn("Failed to lock " + fileName, ex);
  }
}
1
ответ дан OldCurmudgeon 27 August 2018 в 15:12
поделиться

В этом случае вы должны использовать синхронизацию. Представьте, что 2 потока (t1 и t2) одновременно открывают файл и начинают писать на него. Изменения, выполненные первым потоком, перезаписываются вторым потоком, потому что второй поток является последним, чтобы сохранить изменения в файле. Когда поток t1 записывает в файл, t2 должен ждать, пока t1 не закончит его задачу, прежде чем он сможет его открыть.

1
ответ дан Rahul Borkar 27 August 2018 в 15:12
поделиться

может быть проблемой синхронизации потоков?

Да.

Есть ли способ справиться с этим?

Да, убедитесь, что записи сериализованы путем синхронизации на соответствующем мьютексе. Или поочередно, есть только один поток, который фактически выводит в файл, и все остальные потоки просто записывают в очередь текст, который должен быть записан в очередь, из которой извлекается нить записи. (Таким образом, 20 основных потоков не блокируются при вводе-выводе.)

Повторите мьютекс: например, если все они используют один и тот же экземпляр FileWriter (или что-то еще), что я 'fw, то они могут использовать его как мьютекс:

synchronized (fw) {
    fw.write(...);
}

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

Но опять же, если поток, выполняющий ввод-вывод от имени других, вероятно, также является хорошим способом.

27
ответ дан T.J. Crowder 27 August 2018 в 15:12
поделиться

Я предлагаю вам организовать его так: один поток-потребитель будет потреблять все данные и записывать их в файл. Все рабочие потоки будут передавать данные в поток потребителя синхронно. Или при написании нескольких потоков файлов вы можете использовать некоторые реализации мьютексов или блокировок.

9
ответ дан Trenton 27 August 2018 в 15:12
поделиться

Ну, без какой-либо детали реализации, это трудно понять, но, как показывает мой тестовый пример, я всегда получаю 220 строк вывода, т. е. постоянное количество строк, с FileWriter. Обратите внимание, что здесь не используется synchronized.

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
 * Working example of synchonous, competitive writing to the same file.
 * @author WesternGun
 *
 */
public class ThreadCompete implements Runnable {
    private FileWriter writer;
    private int status;
    private int counter;
    private boolean stop;
    private String name;


    public ThreadCompete(String name) {
        this.name = name;
        status = 0;
        stop = false;
        // just open the file without appending, to clear content
        try {
            writer = new FileWriter(new File("test.txt"), true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


    public static void main(String[] args) {

        for (int i=0; i<20; i++) {
            new Thread(new ThreadCompete("Thread" + i)).start();
        }
    }

    private int generateRandom(int range) {
        return (int) (Math.random() * range);
    }

    @Override
    public void run() {
        while (!stop) {
            try {
                writer = new FileWriter(new File("test.txt"), true);
                if (status == 0) {
                    writer.write(this.name + ": Begin: " + counter);
                    writer.write(System.lineSeparator());
                    status ++;
                } else if (status == 1) {
                    writer.write(this.name + ": Now we have " + counter + " books!");
                    writer.write(System.lineSeparator());
                    counter++;
                    if (counter > 8) {
                        status = 2;
                    }

                } else if (status == 2) {
                    writer.write(this.name + ": End. " + counter);
                    writer.write(System.lineSeparator());
                    stop = true;
                }
                writer.flush();
                writer.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Как я понимаю (и тест), в этом процессе есть две фазы:

  • все потоки в пул всех созданных и запущенных, готовый захватить файл;
  • один из них захватывает его, и я предполагаю, что он затем внутренне блокирует его, предотвращает доступ других потоков, потому что я никогда не вижу строки, объединенной с содержимым которые происходят из двух потоков. Поэтому, когда поток пишет, другие ждут, пока он завершит линию, и, скорее всего, выпустит файл. Таким образом, никакого состояния гонки не произойдет.
  • самый быстрый из остальных захватывает файл и начинает писать.

Ну, это точно так же, как толпа, ожидающая снаружи ванной , без очередей .....

Итак, если ваша реализация отличается, покажите код, и мы можем помочь сломать его.

1
ответ дан WesternGun 27 August 2018 в 15:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: