पायथन sqlite3 और संगामिति


87

मेरे पास एक पायथन प्रोग्राम है जो "थ्रेडिंग" मॉड्यूल का उपयोग करता है। प्रत्येक सेकंड में एक बार, मेरा प्रोग्राम एक नया सूत्र शुरू करता है जो वेब से कुछ डेटा प्राप्त करता है, और इस डेटा को मेरी हार्ड ड्राइव में संग्रहीत करता है। मैं इन परिणामों को संग्रहीत करने के लिए sqlite3 का उपयोग करना चाहूंगा, लेकिन मुझे यह काम करने के लिए नहीं मिल सकता है। समस्या निम्न पंक्ति के बारे में प्रतीत होती है:

conn = sqlite3.connect("mydatabase.db")
  • यदि मैं प्रत्येक थ्रेड के अंदर कोड की यह लाइन डालता हूं, तो मुझे एक ऑपरेशनलError मिलती है जो मुझे बताती है कि डेटाबेस फ़ाइल लॉक है। मुझे लगता है कि इसका मतलब यह है कि एक अन्य धागे में एक sqlite3 कनेक्शन के माध्यम से mydatabase.db खुला है और इसे लॉक कर दिया है।
  • यदि मैं मुख्य प्रोग्राम में कोड की यह लाइन डालता हूं और प्रत्येक थ्रेड के लिए कनेक्शन ऑब्जेक्ट (कॉन) पास करता हूं, तो मुझे एक ProgrammingError मिलती है, जिसमें कहा गया है कि किसी थ्रेड में बनाई गई SQLite ऑब्जेक्ट केवल उसी थ्रेड में उपयोग की जा सकती है।

पहले मैं अपने सभी परिणाम CSV फ़ाइलों में संग्रहीत कर रहा था, और इनमें से कोई भी फ़ाइल-लॉकिंग समस्या नहीं थी। उम्मीद है कि यह साइक्लाइट के साथ संभव होगा। कोई विचार?


5
मैं यह नोट करना चाहता हूं कि पायथन के हाल के संस्करणों में sqlite3 के नए संस्करण शामिल हैं जो इस समस्या को ठीक करना चाहिए।
रयान फुगर

@RyanFugger क्या आप जानते हैं कि इसका समर्थन करने वाला सबसे पहला संस्करण कौन सा है? मैं
२.

@RyanFugger AFAIK का कोई पूर्व-निर्मित संस्करण नहीं है जिसमें SQLite3 का एक नया संस्करण है जो कि निश्चित है। आप एक स्वयं का निर्माण कर सकते हैं, हालांकि।
shezi

जवाबों:


44

आप उपभोक्ता-निर्माता पैटर्न का उपयोग कर सकते हैं। उदाहरण के लिए आप कतार बना सकते हैं जो थ्रेड्स के बीच साझा की जाती है। पहला धागा जो वेब से डेटा प्राप्त करता है, इस डेटा को साझा कतार में रखता है। एक और धागा जो डेटाबेस कनेक्शन का मालिक है, कतार से डेटा को हटाता है और इसे डेटाबेस में भेजता है।


8
एफडब्ल्यूआईडब्ल्यू: साइक्लाइट के बाद के संस्करणों का दावा है कि आप थ्रेड्स (कर्सर को छोड़कर) में कनेक्शन और ऑब्जेक्ट साझा कर सकते हैं, लेकिन मैंने वास्तविक अभ्यास में अन्यथा पाया है।
रिचर्ड लेवासेयूर

यहाँ एक उदाहरण है कि एवगेनी लाज़िन ने ऊपर उल्लेख किया है।
मई'09 को

4
एक साझा कतार के पीछे अपने डेटाबेस को छुपाना इस सवाल का एक बहुत बुरा समाधान है क्योंकि एसक्यूएल सामान्य रूप से और SQLite में विशेष रूप से पहले से ही अंतर्निहित लॉकिंग तंत्र हैं, जो संभवतः आपके द्वारा एड-हॉक बनाने वाली किसी भी चीज़ की तुलना में बहुत अधिक परिष्कृत हैं।
shezi

1
आपको प्रश्न पढ़ने की जरूरत है, उस समय कोई अंतर्निहित लॉकिंग तंत्र नहीं था। कई समकालीन एम्बेडेड डेटाबेस में प्रदर्शन कारणों के लिए इस तंत्र का अभाव है (उदाहरण के लिए: LevelDB)।
एवगेनी लाज़िन

179

लोकप्रिय धारणा के विपरीत, sqlite3 के नए संस्करण कई थ्रेड्स से समर्थन का उपयोग करते हैं

इसे वैकल्पिक कीवर्ड तर्क के माध्यम से सक्षम किया जा सकता है check_same_thread:

sqlite.connect(":memory:", check_same_thread=False)

4
मुझे अप्रत्याशित अपवादों का सामना करना पड़ा है और यहां तक ​​कि पायथन क्रैश भी इस विकल्प के साथ होता है (विंडोज 32 पर पायथन 2.7)।
पुनर्मूल्यांकन

4
डॉक्स के अनुसार , मल्टी-थ्रेडेड मोड में एक भी डेटाबेस कनेक्ट को कई थ्रेड्स में उपयोग नहीं किया जा सकता है। एक क्रमबद्ध मोड भी है
केसबश

1
कोई बात नहीं, बस मिल गया: http://sqlite.org/compile.html#threadsafe
Medeiros

1
@FrEaKmAn, क्षमा करें, यह बहुत समय पहले था, यह भी नहीं: स्मृति: डेटाबेस। उसके बाद मैंने कई धागों में साइक्लाइट कनेक्शन साझा नहीं किया।
पुनरावृत्ति

2
@FrEaKmAn, मैंने इसका सामना किया है, बहु-धागा पहुंच पर अजगर प्रक्रिया कोर-डंपिंग के साथ। व्यवहार अप्रत्याशित था, और कोई अपवाद लॉग नहीं किया गया था। अगर मुझे सही से याद है, तो यह लिखा और लिखा दोनों के लिए सच था। यह एक चीज है जिसे मैंने वास्तव में अभी तक अजगर को दुर्घटनाग्रस्त करते देखा है: डी। मैंने इसे थ्रेडसेफ़ मोड में संकलित साइक्लाइट के साथ आज़माया नहीं है, लेकिन उस समय, मेरे पास सिस्टम के डिफॉल्ट साइक्लाइट को पुनः स्थापित करने की स्वतंत्रता नहीं थी। मैंने एरिक को जो सुझाव दिया और थ्रेड
कम्पेटिबिलिटी

17

Mail.python.org.pipermail.1239789 पर निम्न पाया गया है

मैंने इसका हल ढूंढ लिया है। मुझे नहीं पता कि अजगर के प्रलेखन में इस विकल्प के बारे में एक भी शब्द क्यों नहीं है। इसलिए हमें कनेक्शन फ़ंक्शन में एक नया कीवर्ड तर्क जोड़ना होगा और हम अलग-अलग थ्रेड में इससे कर्सर बनाने में सक्षम होंगे। तो उपयोग करें:

sqlite.connect(":memory:", check_same_thread = False)

मेरे लिए पूरी तरह से काम करता है। बेशक अब से मुझे db तक सुरक्षित मल्टीथ्रेडिंग पहुँच का ध्यान रखना होगा। वैसे भी मदद करने की कोशिश के लिए सभी thx।


(GIL के साथ, वास्तव में db के लिए सच्चे मल्टीथ्रेडेड एक्सेस के रास्ते में बहुत कुछ नहीं है जो ive देखा गया है)
Erik Aronesty

चेतावनी : पायथन डॉक्स के पास विकल्प के बारे में यह कहने के लिए check_same_threadहै: "डेटा कनेक्शन से बचने के लिए उपयोगकर्ता द्वारा एक ही कनेक्शन लेखन संचालन के साथ कई थ्रेड्स का उपयोग किया जाना चाहिए।" तो हाँ, आप SQLite का उपयोग कई थ्रेड्स के साथ कर सकते हैं जब तक कि आपका कोड यह सुनिश्चित करता है कि केवल एक धागा किसी भी समय डेटाबेस को लिख सकता है। यदि ऐसा नहीं होता है, तो आप अपने डेटाबेस को भ्रष्ट कर सकते हैं।
Ajedi32

14

मल्टीप्रोसेसिंग पर स्विच करें । यह बहुत बेहतर है, अच्छी तरह से तराजू, कई सीपीयू का उपयोग करके कई कोर के उपयोग से परे जा सकता है, और इंटरफ़ेस अजगर थ्रेडिंग मॉड्यूल का उपयोग करने के समान है।

या, जैसा कि अली ने सुझाव दिया है, बस SQLAlchemy थ्रेड पूलिंग तंत्र का उपयोग करें । यह स्वचालित रूप से आपके लिए सब कुछ संभाल लेगा और इसमें कई अतिरिक्त विशेषताएं हैं, बस उनमें से कुछ को उद्धृत करने के लिए:

  1. SQLAlchemy में SQLite, Postgres, MySQL, Oracle, MS-SQL, Firebird, MaxDB, MS Access, Sybase और Informix के लिए बोलियाँ शामिल हैं; आईबीएम ने एक DB2 ड्राइवर भी जारी किया है। यदि आप SQLite से दूर जाने का फैसला करते हैं तो आपको अपने आवेदन को फिर से लिखना नहीं पड़ता है।
  2. SQLAlchemy के ऑब्जेक्ट रिलेशनल मैपर (ORM) का एक केंद्रीय हिस्सा यूनिट ऑफ़ वर्क सिस्टम, लंबित क्रिएट / इन्सर्ट / अपडेट / डिलीट ऑपरेशंस को कतारों में आयोजित करता है और उन सभी को एक बैच में फ्लश करता है। इसे पूरा करने के लिए यह कतार में सभी संशोधित वस्तुओं का एक सामयिक "निर्भरता प्रकार" करता है ताकि विदेशी प्रमुख बाधाओं का सम्मान किया जा सके, और एक साथ निरर्थक बयानों को समूहित किया जा सके जहां वे कभी-कभी आगे भी बैच सकते हैं। यह अधिकतम क्षमता और लेनदेन सुरक्षा का उत्पादन करता है, और गतिरोध की संभावना को कम करता है।

12

आपको इसके लिए थ्रेड्स का उपयोग नहीं करना चाहिए। यह मुड़ के लिए एक तुच्छ कार्य है और यह संभवतः आपको आगे भी काफी आगे ले जाएगा।

केवल एक सूत्र का उपयोग करें, और अनुरोध को पूरा करने के लिए एक घटना को ट्रिगर करना है।

मुड़ आपके लिए शेड्यूलिंग, कॉलबैक आदि का ध्यान रखेगा। यह आपको एक स्ट्रिंग के रूप में पूरे परिणाम को सौंप देगा, या आप इसे एक स्ट्रीम-प्रोसेसर (मैं एक ट्विटर एपीआई और एक फ्रेंडफीड एपीआई के माध्यम से चला सकता हूं कि दोनों घटनाओं को कॉल करने वालों को आग लगा दें क्योंकि परिणाम अभी भी डाउनलोड हो रहे हैं)।

आप अपने डेटा के साथ क्या कर रहे हैं, इसके आधार पर, आप पूर्ण परिणाम को sqlite में डंप कर सकते हैं जैसे कि यह पूरा हो गया है, इसे पकाएं और इसे डंप करें, या इसे पढ़ते समय पकाएं और इसे अंत में डंप करें।

मेरे पास एक बहुत ही सरल एप्लिकेशन है जो आपको जीथब पर चाहने के करीब है। मैं इसे पफैच (समानांतर भ्रूण ) कहता हूं । यह एक शेड्यूल पर विभिन्न पृष्ठों को पकड़ता है, परिणामों को एक फाइल में स्ट्रीम करता है, और वैकल्पिक रूप से प्रत्येक के सफल समापन पर एक स्क्रिप्ट चलाता है। यह कुछ फैंसी सामान जैसे सशर्त GETs भी करता है, लेकिन फिर भी आप जो भी कर रहे हैं उसके लिए एक अच्छा आधार हो सकता है।


7

या यदि आप मेरी तरह आलसी हैं, तो आप SQLAlchemy का उपयोग कर सकते हैं । यह आपके लिए थ्रेडिंग को हैंडल करेगा, ( थ्रेड लोकल, और कुछ कनेक्शन पूलिंग का उपयोग करके ) और जिस तरह से यह करता है वह भी कॉन्फ़िगर करने योग्य है

अतिरिक्त बोनस के लिए, यदि आपको / जब आपको पता चलता है / तय करना है कि किसी समवर्ती अनुप्रयोग के लिए Sqlite का उपयोग करना एक आपदा होने वाला है, तो आपको MySQL, या Postgres, या कुछ और का उपयोग करने के लिए अपना कोड नहीं बदलना होगा। आप बस स्विच कर सकते हैं।


1
यह आधिकारिक वेबसाइट पर कहीं भी पायथन संस्करण को क्यों निर्दिष्ट नहीं करता है?
प्रदर्शन नाम

3

डेटाबेस में प्रत्येक लेनदेन केsession.close() बाद उपयोग करने की आवश्यकता होती है ताकि एक ही कर्सर का उपयोग करने के लिए बहु-थ्रेड में एक ही कर्सर का उपयोग न करें जो इस त्रुटि का कारण बनता है।



0

मुझे एवगेनी का जवाब पसंद है - कतारें आमतौर पर अंतर-धागा संचार को लागू करने का सबसे अच्छा तरीका है। पूर्णता के लिए, यहां कुछ अन्य विकल्प दिए गए हैं:

  • जब थ्रेडेड थ्रेड्स ने इसका उपयोग करना समाप्त कर लिया है तो DB कनेक्शन को बंद कर दें। यह आपके OperationalErrorओवर को ठीक कर देगा , लेकिन इस तरह के कनेक्शन खोलने और बंद करने का काम आम तौर पर नो-नो है, जो ओवरहेड प्रदर्शन के कारण होता है।
  • बाल सूत्र का उपयोग न करें। यदि एक बार-प्रति सेकंड का कार्य काफी हल्का है, तो आप लाने और स्टोर करने से दूर हो सकते हैं, फिर सही क्षण तक सो सकते हैं। यह अवांछनीय है क्योंकि भ्रूण और स्टोर ऑपरेशन> 1sec ले सकता है, और आपके पास बहु-थ्रेडेड दृष्टिकोण के साथ मल्टीप्लेक्स संसाधनों का लाभ खो देता है।

0

आपको अपने प्रोग्राम के लिए कंसीडर डिजाइन करने की आवश्यकता है। SQLite की स्पष्ट सीमाएँ हैं और आपको उनका पालन करने की आवश्यकता है, FAQ (निम्न प्रश्न भी देखें )।


0

मेरे सवाल का एक संभावित जवाब के रूप में बकवास लगता है। इसका मुख पृष्ठ मेरे सटीक कार्य का वर्णन करता है। (हालांकि मुझे यकीन नहीं है कि कोड कितना स्थिर है।)


0

मैं डेटा दृढ़ता के लिए y_serial पायथन मॉड्यूल पर एक नज़र डालूंगा: http://yserial.sourceforge.net

जो एक SQLite डेटाबेस के आसपास के गतिरोध के मुद्दों को संभालता है। यदि संगामिति की मांग भारी हो जाती है तो स्टोचैस्टिक समय पर लोड को फैलाने के लिए आसानी से कई डेटाबेसों के वर्ग को सेट किया जा सकता है।

आशा है कि यह आपकी परियोजना में मदद करता है ... इसे 10 मिनट में लागू करने के लिए पर्याप्त सरल होना चाहिए।


0

मुझे उपरोक्त किसी भी उत्तर में कोई बेंचमार्क नहीं मिला, इसलिए मैंने सब कुछ बेंचमार्क करने के लिए एक परीक्षण लिखा।

मैंने 3 तरीकों की कोशिश की

  1. SQLite डेटाबेस से क्रमिक रूप से पढ़ना और लिखना
  2. पढ़ने / लिखने के लिए एक ThreadPoolExecutor का उपयोग करना
  3. पढ़ने / लिखने के लिए एक ProcessPoolExecutor का उपयोग करना

बेंचमार्क से परिणाम और takeaways इस प्रकार हैं

  1. अनुक्रमिक पढ़ता / अनुक्रमिक लेखन सबसे अच्छा काम करता है
  2. यदि आपको समानांतर में प्रक्रिया करनी है, तो समानांतर में पढ़ने के लिए ProcessPoolExecutor का उपयोग करें
  3. किसी भी थ्रेडपूल एक्ज़ीक्यूटर का उपयोग करके या ProcessPoolExecutor का उपयोग करके कोई भी प्रदर्शन न करें क्योंकि आप डेटाबेस लॉक की गई त्रुटियों में चलेंगे और आपको फिर से चंक को सम्मिलित करना होगा।

आप मेरे SO उत्तर में बेंचमार्क के लिए कोड और संपूर्ण समाधान पा सकते हैं यहाँ आशा है कि मदद करता है!


-1

लॉक डेटाबेस के साथ त्रुटियों के कारण सबसे अधिक संभावित कारण यह है कि आपको जारी करना चाहिए

conn.commit()

डेटाबेस ऑपरेशन खत्म करने के बाद। यदि आप नहीं करते हैं, तो आपका डेटाबेस राइट-लॉक हो जाएगा और उस तरह से रहेगा। अन्य थ्रेड्स जो लिखने के लिए इंतजार कर रहे हैं, एक समय के बाद टाइम-आउट होंगे (डिफ़ॉल्ट 5 सेकंड के लिए सेट है, http://docs.python.org/2/library/sqlite3.html#sqlite3.connect पर विवरण के लिए देखें ।

सही और समवर्ती सम्मिलन का एक उदाहरण यह होगा:

import threading, sqlite3
class InsertionThread(threading.Thread):

    def __init__(self, number):
        super(InsertionThread, self).__init__()
        self.number = number

    def run(self):
        conn = sqlite3.connect('yourdb.db', timeout=5)
        conn.execute('CREATE TABLE IF NOT EXISTS threadcount (threadnum, count);')
        conn.commit()

        for i in range(1000):
            conn.execute("INSERT INTO threadcount VALUES (?, ?);", (self.number, i))
            conn.commit()

# create as many of these as you wish
# but be careful to set the timeout value appropriately: thread switching in
# python takes some time
for i in range(2):
    t = InsertionThread(i)
    t.start()

यदि आप SQLite को पसंद करते हैं, या अन्य उपकरण हैं जो SQLite डेटाबेस के साथ काम करते हैं, या CSV फ़ाइलों को SQLite db फ़ाइलों के साथ बदलना चाहते हैं, या इंटर-प्लेटफॉर्म IPC की तरह कुछ दुर्लभ करना चाहिए, तो SQLite एक महान उपकरण है और उद्देश्य के लिए बहुत उपयुक्त है। यदि यह सही नहीं लगता है तो अपने आप को एक अलग समाधान का उपयोग करने में दबाव न दें!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.