2017-06-12 5 views
2

私はswap!に原子の値を条件付きで渡すとき、条件がswap!を包むべきか、またはそれが関数swap!の一部でなければならないのでしょうか?上記の例では私のスワップの外側または内側で小切手を走らせるべきですか?関数?

(import '(java.time Instant)) 

(def not-nil? (comp not nil?)) 

(defonce users (atom { 
    "example user 1" {:ts (Instant/now)} 
    "example user 2" {:ts (Instant/now)} 
})) 

(defn update-ts [id] 
    (if (not-nil? (get @users id)) 
    (swap! users assoc-in [id :ts] (Instant/now)))) 

、私はswap!を行う前に、ユーザーのための存在チェックをやっています。しかし、チェックの後、swap!の前にユーザーをusersから削除できませんでしたか?ですから、関数内のチェックをswap!で実行する方が安全ですか?

(defn update-ts [id] 
    (swap! users (fn [users] 
        (if (not-nil? (get users id)) 
         (assoc-in users [id :ts] (Instant/now)) 
         users)))) 
+0

私は状態がスワップを包むべきだと思います。また、デバッグするときにも簡単になるでしょう。 –

+0

@ErtuğrulÇetinそれは私の本来のコードに見られるような自然な本能でした。しかし私は、このチェックとこの特別な 'スワップ! 'の間で原子の状態が変わることを望んでいません。 – DynamiteReed

+0

'swap! 'に渡された関数の内部で検証を行うのが自然ではないと思われる場合は、バリデータ関数を使ってアトムを設定することをお勧めします。 –

答えて

7

しかし、ユーザーがチェックした後、しかしswap!前に、ユーザーから削除することができませんでしたか?ですから、関数内のチェックをswap!で実行する方が安全ですか?

はい、まさに正しいです。そのアトム上のswap!の中のどこからでもアトムを突然変異させる方法について決して決めるべきではありません。 swap!はアトミックであることが保証されている唯一の操作なので、別の方法で(つまり、swap!の外側からアトムに関する決定を下す)たびに競合条件が発生します。

3

しかし、ユーザーはチェックの後にユーザーから削除することはできませんでしたが、スワップする前に !?だから、 関数内のチェックをスワップで実行する方が安全ですか?

amalloyが言ったように、あなたがbulletprootする必要がある場合は、スワップ機能の中にnot-null?のチェックを入れなければなりません。

ただし、&チームが残りのプログラムを書いていることにご注意ください。

  • あなただけのこれまで(ほとんどのプログラムのような)一つのスレッドがある場合は、あなたが競合状態を心配する必要はありません。したがって、あなたはあなたの決定を簡素化することが外に多くの情報を持っています。

  • スレッドが2つ以上ある場合は、マップからエントリを削除しないことがあります(値は:tsのみです)。次に、紛争を心配する必要もありません。

  • 上記の単純な例よりも複雑な関数の場合は、関数にすべてをshoehorningするのではなく、複数のステップをラップするために(dosync ...)フォームを使用します。

3番目のケースでは、​​をrefに置き換えます。例は次のとおりです:

(defonce users (ref {...})) ; ***** must us a ref here ***** 
(dosync 
    (if (not-nil? (get @users id)) 
    <lots of other stuff...> 
    (alter users assoc-in [id :ts] (Instant/now))))) 
+0

これは実際には原子の代わりにrefのかなり良い議論です。この回答が相違点を説明するのに役立つことが分かりました。 https://stackoverflow.com/a/9136699/457586 – DynamiteReed

関連する問題