समवर्ती रूप से उपयोग करने के नियम क्या हैं, ऐसा लगता है कि समवर्ती पहुंच के बारे में नियम अनियंत्रित हैं (हास्केल पक्ष पर) और बस मान लें कि डेवलपर उपयोग किए जाने वाले विशेष बैकएंड से परिचित है। उत्पादन की जरूरतों के लिए यह एक पूरी तरह से वैध धारणा है, लेकिन आकस्मिक प्रोटोटाइप और विकास के लिए यह अच्छा होगा अगर लगातार- * पैकेज थोड़ा अधिक आत्मनिर्भर थे।एक सतत डेटाबेस
तो, निरंतर-स्क्लाइट और परिवार के समवर्ती उपयोग को नियंत्रित करने वाले नियम क्या हैं? जाहिर है, अगर हमारे पास कनेक्शन के पूल हैं, लेकिन कुछ कनेक्शन की पूल बनाने और replicateM x $ forkIO (useThePool connectionPool)
को कॉल करने से नीचे की त्रुटि मिलती है तो कुछ डिग्री की सहमति होनी चाहिए।
user error (SQLite3 returned ErrorBusy while attempting to perform step.)
संपादित करें: कुछ उदाहरण कोड अब नीचे है।
नीचे दिए गए कोड में मैंने 6 धागे को बंद कर दिया (एक मनमाना संख्या - मेरा वास्तविक अनुप्रयोग 3 धागे करता है)। प्रत्येक थ्रेड लगातार स्टोर करता है और एक रिकॉर्ड देखता है (किसी अन्य थ्रेड द्वारा एक्सेस किया जा रहा एक अनूठा रिकॉर्ड, लेकिन इससे कोई फर्क नहीं पड़ता), खेतों में से एक को प्रिंट करना।
{-# LANGUAGE TemplateHaskell, QuasiQuotes
, TypeFamilies, FlexibleContexts, GADTs
, OverloadedStrings #-}
import Control.Concurrent (forkIO, threadDelay)
import Database.Persist
import Database.Persist.Sqlite hiding (get)
import Database.Persist.TH
import Control.Monad
import Control.Monad.IO.Class
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
SomeData
myId Int
myData Double
MyId myId
|]
main = withSqlitePool "TEST" 40 $ \pool -> do
runSqlPool (runMigration migrateAll) pool
mapM_ forkIO [runSqlPool (dbThread i) pool | i <- [0..5]]
threadDelay maxBound
dbThread :: Int -> SqlPersist IO()
dbThread i = forever $ do
x <- getBy (MyId i)
insert (SomeData i (fromIntegral i))
liftIO (print x)
liftIO (threadDelay 100000) -- Just to calm down the CPU,
-- not needed for demonstrating
-- the problem
नायब 40
, TEST
के मूल्यों, और सभी रिकॉर्ड इस उदाहरण के लिए मनमाने ढंग से कर रहे हैं। अधिक मूल्यवान लोगों सहित कई मूल्य, वही व्यवहार करते हैं।
भी ध्यान रखें कि, जबकि यह स्पष्ट रूप से तोड़ा जा सकता है जब आप एक डीबी लेन-देन (runSqlPool
द्वारा शुरू) के अंदर घोंसला एक गैर समाप्त कार्रवाई (forever
के माध्यम से), यह मुख्य मुद्दा नहीं है। आप उन परिचालनों को उलटा कर सकते हैं और लेन-देन को मनमाने ढंग से छोटा कर सकते हैं लेकिन फिर भी आवधिक अपवादों के साथ समाप्त हो जाते हैं।
उत्पादन आमतौर पर है की तरह है:
$ ./so
Nothing
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.)
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.)
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.)
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.)
so: user error (SQLite3 returned ErrorBusy while attempting to perform step.)
so: user error (SQLite3 returned ErrorConstraint while attempting to perform step.)
क्या आप 'useThePool' के बारे में अधिक जानकारी दे सकते हैं? –
@ डैनबर्टन मैंने एक संपादन के माध्यम से अधिक जानकारी दी है। अब उदाहरण कोड के साथ जो शायद उन लोगों के लिए अंधेरा रूप से गलत है जो लगातार के बारे में कुछ भी जानते हैं। –
@ थॉमसएम। डूबुइसन, क्या आपने डालने के बजाय चयन का उपयोग करने का प्रयास किया है, और देखें कि क्या आप त्रुटि को पुन: उत्पन्न कर सकते हैं? अगर त्रुटि चयन पर नहीं होती है, तो त्रुटि कहीं भी फेंक दिया गया डेडलॉक रोकथाम अपवाद हो सकता है, खासकर यदि आप समवर्ती आवेषण करने की कोशिश कर रहे हैं। अगर आपके पास धागा पूल है तो समझ में नहीं आता है। – Sal