идиоматическая блокировка файлов в clojure? - PullRequest
7 голосов
/ 19 июня 2011

У меня есть группа заданий обработки фьючерсов из очереди, которые включают запись в файлы. Какой идиоматический способ обеспечить доступ к конкретному файлу одновременно только одному будущему?

Ответы [ 3 ]

8 голосов
/ 20 июня 2011

Как насчет использования агентов вместо блокировок для обеспечения этого?

Я думаю, что использование агентов для защиты общего изменяемого состояния, независимо от того, находится ли оно в памяти или на диске, более идиоматично по сравнению с использованием блокировок.

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

Например, вот так:

(use 'clojure.contrib.duck-streams)

(defn file-agent [file-name]
  (add-watch (agent nil) :file-writer 
    (fn [key agent old new] 
      (append-spit file-name new))))

(defn async-append [file-agent content]
  (send file-agent (constantly content)))

затем добавьте ваш файл через агента:

(async-append "content written to file" (file-agent "temp-file-name"))

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

(defn sync-append [file-agent content]
  (await (send file-agent (constantly content))))
4 голосов
/ 21 июня 2011

Я бы использовал базовую функцию Clojure lock , которая используется следующим образом:

(locking some-object
  (do-whatever-you-like))

Здесь some-object может быть либо самим файлом, либо, альтернативно, любым произвольным объектом, который выхотите синхронизироваться (что может иметь смысл, если вы хотите использовать одну блокировку для защиты нескольких файлов).

В этом случае используется стандартная блокировка объекта JVM, поэтому она в основном эквивалентна синхронизированному блоку кода в Java.

1 голос
/ 20 июня 2011

Я не думаю, что в Clojure для этого есть специальная встроенная функция, но вы можете использовать стандартные функции Java IO для этого.Это будет выглядеть примерно так:

(import '(java.io File RandomAccessFile))

(def f  (File. "/tmp/lock.file"))
(def channel (.getChannel (RandomAccessFile. f "rw")))
(def lock (.lock channel))
(.release lock)
(.close channel)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...