ফ্লস্কে কি বৈশ্বিক চলকগুলি থ্রেড-নিরাপদ? আমি কীভাবে অনুরোধগুলির মধ্যে ডেটা ভাগ করব?


101

আমার অ্যাপ্লিকেশনটিতে, অনুরোধ করে একটি সাধারণ জিনিসের অবস্থা পরিবর্তন করা হয় এবং প্রতিক্রিয়া রাষ্ট্রের উপর নির্ভর করে।

class SomeObj():
    def __init__(self, param):
        self.param = param
    def query(self):
        self.param += 1
        return self.param

global_obj = SomeObj(0)

@app.route('/')
def home():
    flash(global_obj.query())
    render_template('index.html')

যদি আমি এটি আমার ডেভলপমেন্ট সার্ভারে চালনা করি তবে আমি 1, 2, 3 এবং আরও পাওয়ার আশা করি। যদি একই সাথে 100 টি বিভিন্ন ক্লায়েন্টের কাছ থেকে অনুরোধ করা হয় তবে কিছু ভুল হতে পারে? প্রত্যাশিত ফলাফলটি হ'ল 100 টি পৃথক ক্লায়েন্ট প্রত্যেকে 1 থেকে 100 এর মধ্যে একটি অনন্য নম্বর দেখায় Or বা এর মতো কিছু ঘটবে:

  1. ক্লায়েন্ট 1 প্রশ্ন। self.param1 দ্বারা বর্ধিত হয়।
  2. রিটার্নের স্টেটমেন্ট কার্যকর করার আগে থ্রেডটি ক্লায়েন্ট 2 self.paramএ স্যুইচ করে আবার বর্ধিত হয়।
  3. থ্রেডটি ক্লায়েন্ট 1 এ ফিরে যায় এবং ক্লায়েন্টটি 2 নম্বরটি ফিরে আসে, বলুন।
  4. এখন থ্রেডটি ক্লায়েন্ট 2 এ চলে যায় এবং তাকে 3 নম্বর দেয়।

যেহেতু কেবলমাত্র দুটি ক্লায়েন্ট ছিলেন, তাই প্রত্যাশিত ফলাফলগুলি 2 এবং 3 নয়, 1 এবং 2 ছিল number

আমি আমার অ্যাপ্লিকেশনটি স্কেল করার সাথে সাথে এটি কি ঘটবে? গ্লোবাল ভেরিয়েবলের বিকল্পগুলির দিকে আমার কী নজর দেওয়া উচিত?

উত্তর:


98

এই ধরণের ডেটা ধরে রাখতে আপনি বিশ্বব্যাপী ভেরিয়েবল ব্যবহার করতে পারবেন না। এটি কেবল থ্রেডই নিরাপদ নয়, এটি নিরাপদ প্রক্রিয়া নয় , উত্পাদনে ডাব্লুএসজিআই সার্ভারগুলি একাধিক প্রক্রিয়া চালায়। আপনি যদি অনুরোধগুলি পরিচালনা করতে থ্রেডগুলি ব্যবহার করেন তবে আপনার গণনাগুলিও ভুল হবে না, অনুরোধটি কোন প্রক্রিয়াটি পরিচালনা করেছে তার উপরও নির্ভর করে তারা পৃথক হবে।

বিশ্বব্যাপী ডেটা ধরে রাখতে ফ্লাস্কের বাইরে ডেটা উত্স ব্যবহার করুন। আপনার প্রয়োজনের উপর নির্ভর করে একটি ডাটাবেস, ম্যাকচেড, বা রেডিস হ'ল সমস্ত উপযুক্ত পৃথক স্টোরেজ অঞ্চল। যদি আপনাকে পাইথন ডেটা লোড এবং অ্যাক্সেস করতে হয় তবে বিবেচনা করুন multiprocessing.Manager। আপনি প্রতি ব্যবহারকারী ব্যবহারকারী সাধারণ ডেটার জন্য সেশনটিও ব্যবহার করতে পারেন।


বিকাশ সার্ভার একক থ্রেড এবং প্রক্রিয়াতে চলতে পারে। প্রতিটি অনুরোধ সিঙ্ক্রোনালি হ্যান্ডেল করা হওয়ায় আপনি যে আচরণটি বর্ণনা করছেন তা দেখতে পাবেন না। থ্রেড বা প্রক্রিয়া সক্ষম করুন এবং আপনি এটি দেখতে পাবেন। app.run(threaded=True)বা app.run(processes=10)। (1.0 এ সার্ভারটি ডিফল্টরূপে থ্রেড করা হয়েছে।)


কিছু ডাব্লুএসজিআই সার্ভার জেন্ট বা অন্য একটি এসিএনসি কর্মীকে সমর্থন করতে পারে। গ্লোবাল ভেরিয়েবলগুলি এখনও থ্রেড নিরাপদ নয় কারণ এখনও বেশিরভাগ জাতি শর্তের বিরুদ্ধে কোনও সুরক্ষা নেই। আপনি এখনও এমন পরিস্থিতিতে থাকতে পারেন যেখানে একজন শ্রমিক একটি মান পায়, ফলন দেয়, অন্যজন এটিকে সংশোধন করে, ফলন দেয়, তারপরে প্রথম কর্মীও এটিকে সংশোধন করে।


কোনও অনুরোধ চলাকালীন আপনার যদি কিছু বিশ্বব্যাপী ডেটা সঞ্চয় করতে হয় তবে আপনি ফ্লাস্কের gঅবজেক্টটি ব্যবহার করতে পারেন । আর একটি সাধারণ কেস হ'ল কিছু শীর্ষ-স্তরের অবজেক্ট যা ডাটাবেস সংযোগ পরিচালনা করে। এই ধরণের "গ্লোবাল" এর পার্থক্য হ'ল এটি প্রতিটি অনুরোধের জন্য অনন্য, অনুরোধগুলির মধ্যে ব্যবহৃত হয় না এবং সংস্থানটির সেট আপ এবং টিয়ারডাউন পরিচালনা করার মতো কিছু রয়েছে।


30

এটি বিশ্বব্যাপী থ্রেড সুরক্ষার কোনও উত্তর নয়।

তবে আমি মনে করি এখানে অধিবেশনগুলি উল্লেখ করা জরুরী। আপনি ক্লায়েন্ট-নির্দিষ্ট ডেটা সঞ্চয় করার উপায় খুঁজছেন। প্রতিটি সংযোগের নিজস্ব থ্রেডফায়া উপায়ে ডেটা পুলে অ্যাক্সেস থাকা উচিত।

সার্ভার-সাইড সেশনগুলির মাধ্যমে এটি সম্ভব এবং এটি খুব ঝরঝরে ফ্লাস্ক প্লাগইনে পাওয়া যায়: https://pythonhosted.org/Flask-Session/

আপনি যদি সেশনগুলি সেট আপ করেন, sessionআপনার সমস্ত রুটে একটি চলক উপলব্ধ এবং এটি অভিধানের মতো আচরণ করে। এই অভিধানে সঞ্চিত ডেটা প্রতিটি সংযুক্ত ক্লায়েন্টের জন্য পৃথক।

এখানে একটি সংক্ষিপ্ত ডেমো:

from flask import Flask, session
from flask_session import Session

app = Flask(__name__)
# Check Configuration section for more details
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)

@app.route('/')
def reset():
    session["counter"]=0

    return "counter was reset"

@app.route('/inc')
def routeA():
    if not "counter" in session:
        session["counter"]=0

    session["counter"]+=1

    return "counter is {}".format(session["counter"])

@app.route('/dec')
def routeB():
    if not "counter" in session:
        session["counter"] = 0

    session["counter"] -= 1

    return "counter is {}".format(session["counter"])


if __name__ == '__main__':
    app.run()

পরে pip install Flask-Session, আপনি এটি চালাতে সক্ষম হওয়া উচিত। এটি বিভিন্ন ব্রাউজার থেকে অ্যাক্সেস করার চেষ্টা করুন, আপনি দেখতে পাবেন যে কাউন্টারটি তাদের মধ্যে ভাগ করা নেই।


3

পূর্ববর্তী উর্ধ্বতন উত্তরগুলি সম্পূর্ণরূপে স্বীকার করার সময়, ফ্ল্যাশ 'ডেভলপমেন্ট সার্ভার'-এর অধীনে প্রোটোটাইপিং বা সত্যই সরল সার্ভারের উদ্দেশ্যে, উত্পাদন এবং স্কেলযোগ্য ফ্লাস্ক স্টোরেজের জন্য বিশ্বব্যাপী পরিবর্তনগুলি ব্যবহারকে নিরুৎসাহিত করার সময় ...

...

পাইথন বিল্ট-ইন ধরনের তথ্য, এবং আমি ব্যক্তিগতভাবে ব্যবহার করা হয় এবং বিশ্বব্যাপী পরীক্ষিত dict, যেমন পাইথন ডকুমেন্টেশন প্রতি হয় থ্রেড নিরাপদ। না প্রক্রিয়া নিরাপদ।

এই জাতীয় (সার্ভার গ্লোবাল) ডিক থেকে সন্নিবেশ, অনুসন্ধান এবং পঠনগুলি প্রতিটি (সম্ভবত সমবর্তী) বিকাশ সার্ভারের অধীনে চলমান ফ্লাস্ক সেশন থেকে ঠিক হবে।

যখন এই জাতীয় গ্লোবাল ডিকটি কোনও অনন্য ফ্লাস্ক সেশন কী দ্বারা চিহ্নিত করা হয়, তখন এটি সেশনের নির্দিষ্ট ডেটা সার্ভার-সাইড স্টোরেজ করার জন্য কার্যকর হতে পারে অন্যথায় কুকিতে ফিট না করে (সর্বাধিক আকার 4 কেবি)।

অবশ্যই, এই জাতীয় সার্ভারের গ্লোবাল ডিকটি স্মৃতিশক্তি থাকার কারণে খুব বড় হওয়ার জন্য সাবধানে রক্ষা করা উচিত। অনুরোধ প্রসেসিংয়ের সময় 'পুরানো' কী / মান জুটির মেয়াদ শেষ হওয়ার কোনও ধরণের কোড কোড করা যেতে পারে।

আবার এটি উত্পাদন বা স্কেলযোগ্য মোতায়েনের জন্য প্রস্তাবিত নয়, তবে সম্ভবত স্থানীয় টাস্ক-ওরিয়েন্টেড সার্ভারগুলির ক্ষেত্রে ঠিক আছে যেখানে প্রদত্ত টাস্কের জন্য পৃথক ডাটাবেস খুব বেশি।

...

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.