2013-05-10 2 views
37

SQLAlchemyTornadoasync पर कैसे बनाया जाए? मुझे async mongo example पर मोंगोडीबी के लिए उदाहरण मिला लेकिन मुझे motorSQLAlchemy के लिए कुछ भी नहीं मिला। क्या किसी को SQLAlchemytornado.gen के साथ निष्पादित करने के लिए प्रश्न बनाने के बारे में पता है (मैं SQLAlchemy से नीचे उपयोग कर रहा हूं, इस समय मेरे हैंडलर डेटाबेस से पढ़ते हैं और परिणाम लौटाते हैं, मैं इसे एसिंक बनाना चाहता हूं)।टॉरनाडो में एसक्यूएलकेमी को एसिंक होने के लिए कैसे बनाया जाए?

+1

चेकआउट: http://pylover.dobisel.com/posts/aiopg-aiopg_sa-and-aiopg8000/ – pylover

उत्तर

68

ORM स्पष्ट एसिंक्रोनस प्रोग्रामिंग के लिए खराब रूप से उपयुक्त हैं, यानी, जहां प्रोग्रामर को किसी भी समय नेटवर्क कॉल का उपयोग करने वाले कुछ स्पष्ट कॉलबैक उत्पन्न करना चाहिए। इसके लिए एक प्राथमिक कारण यह है कि ओआरएम lazy loading पैटर्न का व्यापक उपयोग करते हैं, जो स्पष्ट async के साथ कम या कम असंगत है। कोड है कि इस तरह दिखता है:

user = Session.query(User).first() 
print user.addresses 

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

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

def execute(connection, statement): 
    cursor = connection.cursor() 
    cursor.execute(statement) 
    results = cursor.fetchall() 
    cursor.close() 
    return results 

ऊपर कोड करता है क्या एक कनेक्शन पर एक एसक्यूएल बयान को क्रियान्वित करने, एक साधारण संचालन हो रहा है। लेकिन पूरी तरह से async डीबीएपीआई का उपयोग psycopg2 के async एक्सटेंशन की तरह, आईओ पर उपरोक्त कोड ब्लॉक कम से कम तीन बार। तो उपर्युक्त कोड को स्पष्ट एसिंक शैली में लिखने के लिए, यहां तक ​​कि जब उपयोग में कोई एसिंक इंजन नहीं है और कॉलबैक वास्तव में अवरुद्ध नहीं होते हैं, तो इसका मतलब है कि उपर्युक्त बाहरी फ़ंक्शन कॉल कम से कम तीन फ़ंक्शन कॉल बन जाती है, बजाय ओवरहेड लगाया जाता है स्पष्ट एसिंक्रोनस सिस्टम या डीबीएपीआई द्वारा स्वयं को कॉल किया जाता है। तो एक सरल आवेदन स्वचालित रूप से कथन निष्पादन के आसपास एक साधारण अमूर्तता के आस-पास फ़ंक्शन कॉल ओवरहेड के 3x का जुर्माना दिया जाता है। और पायथन में, function call overhead is everything

इन कारणों से, मैं स्पष्ट एसिंक सिस्टम के आसपास प्रचार के बारे में उत्साहित से कम होना जारी रखता हूं, कम से कम डिग्री के लिए कुछ लोग वेब पृष्ठों को वितरित करने जैसी सभी चीज़ों के लिए सभी async जाना चाहते हैं (node.js देखें)। मैं इसके बजाए अंतर्निहित एसिंक सिस्टम का उपयोग करने की सिफारिश करता हूं, विशेष रूप से gevent, जहां आपको एसिंक्रोनस मॉडल के सभी गैर-अवरुद्ध आईओ लाभ और स्पष्ट कॉलबैक के संरचनात्मक क्रियापद/डाउनसाइड्स में से कोई भी नहीं मिलता है। मैं इन दो दृष्टिकोणों के लिए उपयोग के मामलों को समझने की कोशिश करना जारी रखता हूं, इसलिए मैं सभी समस्याओं के समाधान के रूप में स्पष्ट एसिंक दृष्टिकोण की अपील से परेशान हूं, यानी जैसा कि आप नोड के साथ देखते हैं।जेएस - हम वर्बोजिटी और कोड जटिलता को कम करने के लिए पहली जगह में स्क्रिप्टिंग भाषाओं का उपयोग कर रहे हैं, और वेब पेजों को वितरित करने जैसी सरल चीजों के लिए स्पष्ट एसिंक कुछ भी नहीं करता है लेकिन बॉयलरप्लेट जोड़ता है जो कि गीवेंट या इसी तरह से स्वचालित हो सकता है, यदि आईओ को अवरुद्ध करना इस तरह के मामले में ऐसी समस्या है (उच्च मात्रा वाली वेबसाइटें सिंक्रोनस आईओ मॉडल के साथ ठीक होती हैं)। गीवेंट-आधारित सिस्टम उत्पादन सिद्ध हैं और उनकी लोकप्रियता बढ़ रही है, इसलिए यदि आपको ओआरएम प्रदान करने वाले कोड स्वचालन पसंद हैं, तो आप एसिंक-आईओ-शेड्यूलिंग स्वचालन को भी गले लगा सकते हैं जो कि गीवेंट प्रदान करता है।

अद्यतन: निक कोग्लान ने अपने great article on the subject of explicit vs. implicit async को इंगित किया जो कि यहां भी पढ़ना चाहिए। और मुझे इस तथ्य को भी अपडेट किया गया है कि pep-3156 now welcomes interoperability with gevent, गीवेन्ट में पहले बताए गए विचलन को उलट देता है, जो कि निक के लेख के लिए काफी हद तक धन्यवाद देता है। तो भविष्य में मैं इन दृष्टिकोणों को एकीकृत करने की प्रणाली उपलब्ध होने के बाद डेटाबेस तर्क के लिए भूगर्भ का उपयोग करके टॉरनाडो के एक संकर की सिफारिश करूंगा।

+1

इस उत्तर के पोस्टिंग के बाद से 4 साल बीत चुके हैं। मुझे आश्चर्य है, zzzeek, ​​या समुदाय में किसी भी अन्य लोग। क्या उनके पास ओआरएम परिदृश्य, और टोरनाडो, या गीवेंट में इस उत्तर की समीक्षा की गारंटी देने के लिए कोई महत्वपूर्ण बदलाव आया है? मैं पूछ रहा हूं क्योंकि मुझे संभावित रूप से इस मुद्दे का सामना करना पड़ रहा है: https://stackoverflow.com/questions/44599402/what-is-a-good-way-to-organize-your-models-connections-if-one-wants- टू-यूज-स्क्ला बोके सर्वर अनुप्रयोग टोरनाडो का उपयोग करते हैं, और मुझे इससे जानकारी प्राप्त करने के लिए डीबी से कनेक्ट करने की आवश्यकता है। – Thornhale

+3

हमेशा के रूप में एक ही जवाब ... व्यापार और दृढ़ता तर्क गैर ब्लॉकिंग आईओ के लिए कोई ज़रूरत नहीं है। यदि आपको एक वेब ढांचे का उपयोग करने के लिए मजबूर किया जाता है जो सबकुछ "स्पष्ट एसिंक" होने के लिए मजबूर करता है, तो सबसे अच्छा समाधान एक है)। फ्लास्क या पिरामिड या उस बी से कम सामान्य वेब ढांचे का प्रयोग करें। एक थ्रेड पूल का प्रयोग करें – zzzeek

23

मेरे पास अतीत में एक ही समस्या थी और मुझे विश्वसनीय Async-MySQL लाइब्रेरी नहीं मिल सका। हालांकि Asyncio + पोस्टग्रेस का उपयोग करके एक अच्छा समाधान है।

import asyncio 
from aiopg.sa import create_engine 
import sqlalchemy as sa 


metadata = sa.MetaData() 

tbl = sa.Table('tbl', metadata, 
      sa.Column('id', sa.Integer, primary_key=True), 
      sa.Column('val', sa.String(255))) 

@asyncio.coroutine 
def go(): 
    engine = yield from create_engine(user='aiopg', 
             database='aiopg', 
             host='127.0.0.1', 
             password='passwd') 

    with (yield from engine) as conn: 
     yield from conn.execute(tbl.insert().values(val='abc')) 

     res = yield from conn.execute(tbl.select().where(tbl.c.val=='abc')) 
     for row in res: 
      print(row.id, row.val) 


loop = asyncio.get_event_loop() 
loop.run_until_complete(go()) 
2

मैं अगले रास्ते में SQLAlchemy के साथ बवंडर उपयोग कर रहा हूँ:

 

from tornado_mysql import pools 
from sqlalchemy.sql import table, column, select, join 
from sqlalchemy.dialects import postgresql, mysql 

# from models import M, M2 

t = table(...) 
t2 = table(...) 

xxx_id = 10 

j = join(t, t2, t.c.t_id == t2.c.id) 
s = select([t]).select_from(j).where(t.c.xxx == xxx_id) 

sql_str = s.compile(dialect=mysql.dialect(),compile_kwargs={"literal_binds": True}) 


pool = pools.Pool(conn_data...) 
cur = yield pool.execute(sql_str) 
data = cur.fetchone() 
 

उस मामले में हम करने में सक्षम हैं तुम बस aiopg पुस्तकालय है, जो बॉक्स से बाहर SQLAlchemy समर्थन के साथ आता उपयोग करने की आवश्यकता निर्माण प्रश्नों के लिए sqlalchemy मॉडल, और sqlalchemy उपकरण का उपयोग करें।

1

बवंडर नहीं है, लेकिन हम GINO project में asyncio में बनाया SQLAlchemy async की प्रकार:

import asyncio 
from gino import Gino, enable_task_local 
from sqlalchemy import Column, Integer, Unicode, cast 

db = Gino() 


class User(db.Model): 
    __tablename__ = 'users' 

    id = Column(Integer(), primary_key=True) 
    nickname = Column(Unicode(), default='noname') 


async def main(): 
    await db.create_pool('postgresql://localhost/gino') 

    # Create object, `id` is assigned by database 
    u1 = await User.create(nickname='fantix') 
    print(u1.id, u1.nickname) # 1 fantix 

    # Retrieve the same row, as a different object 
    u2 = await User.get(u1.id) 
    print(u2.nickname) # fantix 

    # Update affects only database row and the operating object 
    await u2.update(nickname='daisy') 
    print(u2.nickname) # daisy 
    print(u1.nickname) # fantix 

    # Returns all user objects with "d" in their nicknames 
    users = await User.query.where(User.nickname.contains('d')).gino.all() 

    # Find one user object, None if not found 
    user = await User.query.where(User.nickname == 'daisy').gino.first() 

    # Execute complex statement and return command status 
    status = await User.update.values(
     nickname='No.' + cast(User.id, Unicode), 
    ).where(
     User.id > 10, 
    ).gino.status() 

    # Iterate over the results of a large query in a transaction as required 
    async with db.transaction(): 
     async for u in User.query.order_by(User.id).gino.iterate(): 
      print(u.id, u.nickname) 


loop = asyncio.get_event_loop() 
enable_task_local(loop) 
loop.run_until_complete(main()) 

यह थोड़ा की तरह दिखता है, लेकिन वास्तव में काफी अलग SQLAlchemy ORM से। चूंकि हमने स्क्लेक्लेमी कोर का केवल एक हिस्सा उपयोग किया था, और इसके शीर्ष पर एक साधारण ओआरएम बनाया था। यह नीचे asyncpg का उपयोग करता है, इसलिए यह केवल के लिए PostgreSQL के लिए है।

अद्यतन: जीआईएनओ व्लादिमीर गोंचारोव के योगदान के लिए धन्यवाद, अब टोरनाडो का समर्थन करता है। docs here

संबंधित मुद्दे