পাইথনে একটি ফাইল লক করা হচ্ছে


152

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

উত্তর:


115

ঠিক আছে, তাই আমি এখানে আমার লেখা কোডটি দিয়ে শেষ করেছি , আমার ওয়েবসাইটের লিঙ্কটি মারা গেছে, আর্কাইভ.অর্গে দেখুন ( গিটহাবটিতেও উপলভ্য )। আমি এটি নিম্নলিখিত ফ্যাশনে ব্যবহার করতে পারি:

from filelock import FileLock

with FileLock("myfile.txt.lock"):
    print("Lock acquired.")
    with open("myfile.txt"):
        # work with the file as it is now locked

10
ব্লগ পোস্টে একটি মন্তব্য দ্বারা উল্লিখিত হিসাবে, এই সমাধানটি "নিখুঁত" নয়, যাতে প্রোগ্রামটির এমনভাবে শেষ করা সম্ভব হয় যে লকটি জায়গায় রেখে দেওয়া হয় এবং আপনাকে ফাইলের আগে নিজেই লকটি মুছতে হবে আবার অ্যাক্সেসযোগ্য হয়ে ওঠে। যাইহোক, যে একপাশে, এটি এখনও একটি ভাল সমাধান।
leetNightshade

3
তবুও ইভানের ফাইললকের আরও একটি উন্নত সংস্করণ পাওয়া যাবে: github.com/ilastik/lazyflow/blob/master/lazyflow/utility/…
স্টুয়ার্ট বার্গ

3
ওপেনস্ট্যাকটি তাদের নিজস্ব (ভাল, এড়িয়ে চলুন মন্টানারোর) বাস্তবায়ন প্রকাশ করেছে - পাইকফাইলে - আগের মন্তব্যে উল্লিখিতগুলির সাথে খুব মিল, তবে এখনও একবার দেখার মতো।
jweyrich

7
@ জ্যুইরিচ ওপেনস্ট্যাকস পাইলকফিল এখন হ্রাস করা হয়েছে। পরিবর্তে এটি ফাস্টেনার বা oslo.concurrency ব্যবহার করার পরামর্শ দেওয়া হয় ।
harbun

2
আর একটি অনুরূপ বাস্তবায়ন আমার অনুমান: github.com/benediktschmitt/py-filelock
হেরি

39

এখানে একটি ক্রস-প্ল্যাটফর্ম ফাইল লকিং মডিউল রয়েছে: পোর্টালকার

যদিও কেভিন বলেছেন, একযোগে একাধিক প্রক্রিয়া থেকে কোনও ফাইলকে লেখার বিষয়টি আপনি যদি সম্ভব হয় তবে এড়াতে চান।

আপনি যদি কোনও সমস্যাটিকে কোনও ডাটাবেসে জুতা দিতে পারেন তবে আপনি এসকিউএলাইট ব্যবহার করতে পারেন। এটি সমবর্তী অ্যাক্সেস সমর্থন করে এবং এর নিজস্ব লকিং পরিচালনা করে।


16
+1 - এসকিউএলাইট প্রায় সবসময় এই ধরণের পরিস্থিতিতে যাওয়ার উপায়।
সিডলারি

2
Portalocker এর জন্য উইন্ডোজটির জন্য পাইথন এক্সটেনশনগুলি প্রয়োজন।
n611x007

2
@ ন্যাক্সা এর একটি বৈকল্পিক রয়েছে যা কেবলমাত্র এমএসভিসিআরটি এবং সিটিপিতে নির্ভর করে, রাউন্ডআপ.hg.sourceforge.net/hgweb/roundup/roundup/file/tip/… দেখুন
দ্য ক্যাট

@ n611x007 Portalocker সবেমাত্র আপডেট হয়েছে তাই এটি উইন্ডোতে আর কোনও এক্সটেনশনের প্রয়োজন নেই :)
ওল্ফ

2
এসকিউএলাইট সমবর্তী অ্যাক্সেস সমর্থন করে?
পাইওটর

23

অন্যান্য সমাধানগুলি প্রচুর বহিরাগত কোড বেসগুলি উদ্ধৃত করে। আপনি যদি নিজেরাই এটি করতে পছন্দ করেন তবে এখানে ক্রস-প্ল্যাটফর্ম সমাধানের জন্য কিছু কোড রয়েছে যা লিনাক্স / ডস সিস্টেমে সম্পর্কিত ফাইল লকিং সরঞ্জাম ব্যবহার করে।

try:
    # Posix based file locking (Linux, Ubuntu, MacOS, etc.)
    import fcntl, os
    def lock_file(f):
        fcntl.lockf(f, fcntl.LOCK_EX)
    def unlock_file(f):
        fcntl.lockf(f, fcntl.LOCK_UN)
except ModuleNotFoundError:
    # Windows file locking
    import msvcrt, os
    def file_size(f):
        return os.path.getsize( os.path.realpath(f.name) )
    def lock_file(f):
        msvcrt.locking(f.fileno(), msvcrt.LK_RLCK, file_size(f))
    def unlock_file(f):
        msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, file_size(f))


# Class for ensuring that all file operations are atomic, treat
# initialization like a standard call to 'open' that happens to be atomic.
# This file opener *must* be used in a "with" block.
class AtomicOpen:
    # Open the file with arguments provided by user. Then acquire
    # a lock on that file object (WARNING: Advisory locking).
    def __init__(self, path, *args, **kwargs):
        # Open the file and acquire a lock on the file before operating
        self.file = open(path,*args, **kwargs)
        # Lock the opened file
        lock_file(self.file)

    # Return the opened file object (knowing a lock has been obtained).
    def __enter__(self, *args, **kwargs): return self.file

    # Unlock the file and close the file object.
    def __exit__(self, exc_type=None, exc_value=None, traceback=None):        
        # Flush to make sure all buffered contents are written to file.
        self.file.flush()
        os.fsync(self.file.fileno())
        # Release the lock on the file.
        unlock_file(self.file)
        self.file.close()
        # Handle exceptions that may have come up during execution, by
        # default any exceptions are raised to the user.
        if (exc_type != None): return False
        else:                  return True        

এখন, AtomicOpenএমন একটি withব্লকে ব্যবহার করা যেতে পারে যেখানে কেউ সাধারণত একটি openবিবৃতি ব্যবহার করে ।

সতর্কতা: যদি উইন্ডোজ এবং পাইথনগুলিতে চলতে থাকে প্রস্থান বলার আগে ক্র্যাশ হয়, তবে লক আচরণটি কী হবে তা আমি নিশ্চিত নই।

সতর্কতা: এখানে সরবরাহ করা লকিং পরামর্শমূলক, পরম নয়। সমস্ত সম্ভাব্য প্রতিযোগিতামূলক প্রক্রিয়াগুলিতে অবশ্যই "অ্যাটমিক ওপেন" শ্রেণিটি ব্যবহার করা উচিত।


unlock_fileলিনাক্সের ফাইলটি fcntlআবার LOCK_UNপতাকা সহ কল করা উচিত নয় ?
ইডমাস্টার

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

ইন __exit__আপনি closeবাহিরে পর লক unlock_file। আমি বিশ্বাস করি রানটাইম সময় ডেটা ফ্লাশ করতে পারে (অর্থাত্ লিখিত) close। আমি বিশ্বাস করি যে অবশ্যই লকের বাইরে কোনও অতিরিক্ত ডেটা লেখা নেই তা নিশ্চিত করতে অবশ্যই একটি flushএবং fsyncলকের নীচে থাকা আবশ্যক close
বেনজামিন ব্যানিয়ার

সংশোধনীর জন্য ধন্যবাদ! আমি যাচাই যে হয় ছাড়া একটি জাতি অবস্থার জন্য সম্ভাবনা flushএবং fsync। কল করার আগে আপনার প্রস্তাবিত দুটি লাইন আমি যুক্ত করেছি unlock। আমি পুনরায় পরীক্ষা করেছি এবং রেসের শর্তটি সমাধান হয়ে গেছে বলে মনে হচ্ছে।
টমাস লাক্স

1
"ভুল" হয়ে যাওয়ার একমাত্র বিষয়টি হ'ল সময় প্রক্রিয়া অনুসারে 1 ফাইলটি লক করে এর বিষয়বস্তুগুলি কেটে ফেলা হবে (সামগ্রীগুলি মুছে ফেলা হবে)। লক হওয়ার আগে উপরের কোডটিতে "ডাব্লু" দিয়ে অন্য একটি ফাইল "ওপেন" যুক্ত করে আপনি নিজে এটি পরীক্ষা করতে পারেন । এটি অবশ্যম্ভাবী নয়, কারণ লক করার আগে আপনাকে অবশ্যই ফাইলটি খুলতে হবে। স্পষ্ট করার জন্য, "পারমাণবিক" এই অর্থে যে কেবলমাত্র একটি ফাইলের মধ্যে বৈধ ফাইলের বিষয়বস্তু পাওয়া যাবে। এর অর্থ হ'ল আপনি একসাথে মিশ্রিত একাধিক প্রতিযোগিতামূলক প্রক্রিয়াগুলির সামগ্রীগুলির সাথে কোনও ফাইল পাবেন না।
থমাস লাক্স

15

আমি লকফিল পছন্দ করি - প্ল্যাটফর্ম-স্বতন্ত্র ফাইল লকিং


3
এই গ্রন্থাগারটি ভাল লেখা রয়েছে বলে মনে হয়, তবে বাসি লক ফাইলগুলি সনাক্ত করার কোনও ব্যবস্থা নেই। এটি লক তৈরি করেছে এমন পিআইডি ট্র্যাক করে, তাই প্রক্রিয়াটি এখনও চলছে কিনা তা বলা উচিত।
শেরবাং


@ জানুস ট্রয়েলস পিডলকফায়াল মডিউলটি কোনওভাবেই লকগুলি গ্রহণ করবে না।
শেরবাং

@ শেরবাং আপনি কি নিশ্চিত? এটি O_CREAT | O_EXCL মোডের মাধ্যমে লক ফাইলটি খুলবে।
মুহস্মীথ

2
অনুগ্রহ করে নোট করুন যে এই গ্রন্থাগারটি সুপারসাইড
কংগ্রেসবঙ্গাস

13

আমি এটি করার জন্য বেশ কয়েকটি সমাধান খুঁজছি এবং আমার পছন্দটি oslo.concurrency হয়েছে rency

এটি শক্তিশালী এবং তুলনামূলকভাবে ভাল নথিভুক্ত। এটি ফাস্টেনারদের উপর ভিত্তি করে।

অন্যান্য সমাধান:


পুনরায়: Portalocker, আপনি এখন পাইপুইউন 32 প্যাকেজের মাধ্যমে পাইপের মাধ্যমে পাইউইন 32 ইনস্টল করতে পারেন।
টিমোথি জান্নাস


13

লক করা প্ল্যাটফর্ম এবং ডিভাইস নির্দিষ্ট, তবে সাধারণত আপনার কয়েকটি বিকল্প থাকে:

  1. ফ্লক () বা সমতুল্য (যদি আপনার ওএস সমর্থন করে) ব্যবহার করুন। এটি পরামর্শদাতাকে লক করা হয়, যদি না আপনি লকটি পরীক্ষা করেন তবে তা উপেক্ষা করা হবে।
  2. লক-অনুলিপি-মুভ-আনলক পদ্ধতিটি ব্যবহার করুন, যেখানে আপনি ফাইলটি অনুলিপি করেন, নতুন ডেটা লিখুন, তারপরে এটি সরিয়ে নিন (সরান, অনুলিপি করুন না - সরানো লিনাক্সে একটি পারমাণবিক ক্রিয়াকলাপ - আপনার ওএস পরীক্ষা করুন), এবং আপনি পরীক্ষা করে দেখুন লক ফাইলের অস্তিত্ব।
  3. "লক" হিসাবে একটি ডিরেক্টরি ব্যবহার করুন। আপনি যদি এনএফএসে লিখছেন তবে এটি প্রয়োজনীয়, যেহেতু এনএফএস পলকে () সমর্থন করে না।
  4. প্রক্রিয়াগুলির মধ্যে ভাগ করে নেওয়া মেমরি ব্যবহার করার সম্ভাবনাও রয়েছে, তবে আমি কখনও চেষ্টা করে দেখিনি; এটি খুব ওএস-নির্দিষ্ট

এই সমস্ত পদ্ধতির জন্য, আপনাকে লকটি অর্জন এবং পরীক্ষা করার জন্য একটি স্পিন-লক (পুনরায় ব্যর্থতার পরে চেষ্টা) কৌশল ব্যবহার করতে হবে। এটি ভুল-সিঙ্ক্রোনাইজেশনের জন্য একটি ছোট উইন্ডো ছেড়ে দেয়, তবে এটি সাধারণভাবে যথেষ্ট ছোট একটি বড় সমস্যা নয় be

যদি আপনি এমন কোনও সমাধান খুঁজছেন যা ক্রস প্ল্যাটফর্ম, তবে আপনি অন্য কোনও সিস্টেমের মাধ্যমে অন্য সিস্টেমে লগইন করা ভাল (পরবর্তী সর্বোত্তম জিনিসটি উপরের এনএফএস কৌশল)।

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


4
দ্রষ্টব্য: সরানো / পুনর্নামকরণ উইন 32 এ পারমাণবিক নয়। রেফারেন্স: stackoverflow.com/questions/167414/...
sherbang

4
নতুন দ্রষ্টব্য: os.renameপাইথন ৩.৩ থেকে উইন32-
বিএসইউ

7

ওএস স্তরে একক ফাইলে অ্যাক্সেসের সমন্বয় করা এমন সমস্ত ধরণের সমস্যার সাথে পরিপূর্ণ যা আপনি সম্ভবত সমাধান করতে চান না।

আপনার সেরা বেটে একটি পৃথক প্রক্রিয়া রয়েছে যা সেই ফাইলটিতে পঠন / লেখার অ্যাক্সেসকে সমন্বয় করে।


19
"পৃথক প্রক্রিয়া যা সেই ফাইলটিতে অ্যাক্সেস পড়ার / লেখার সমন্বয় সাধন করে" - অন্য কথায়, একটি ডাটাবেস সার্ভার প্রয়োগ করে :-)
এলি বেন্ডারস্কি

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

9
-1 কারণ এটি ব্যাখ্যা ছাড়াই কেবল এফইউডি। লেখার জন্য একটি ফাইল লক করা আমার কাছে বেশ সোজা ধারণা বলে মনে হচ্ছে যে ওএস যেমন ফাংশন দিয়ে থাকেflock । "আপনার নিজের মিউটেক্সগুলি রোল করুন এবং সেগুলি পরিচালনা করার জন্য একটি ডেমন প্রক্রিয়া" মনে হচ্ছে সমাধানের জন্য নেওয়া একটি চূড়ান্ত এবং জটিল পদ্ধতির মতো বলে মনে হচ্ছে ... এমন একটি সমস্যা যা আপনি বাস্তবে আমাদের জানাননি, তবে কেবলমাত্র উদ্বেগজনকভাবে প্রস্তাবিত উপস্থিত রয়েছে।
মার্ক আমেরিকা

-১ @ মার্ক অ্যামেরির দেওয়া কারণগুলির জন্য, পাশাপাশি ওপি কোন বিষয়গুলি সমাধান করতে চায় সে সম্পর্কে একটি অসমর্থিত মতামত দেওয়ার জন্য
মাইকেল ক্রেবস

5

একটি ফাইল লক করা সাধারণত একটি প্ল্যাটফর্ম-নির্দিষ্ট অপারেশন হয়, তাই আপনাকে বিভিন্ন অপারেটিং সিস্টেমে চলার সম্ভাবনাটি মঞ্জুর করতে হতে পারে। উদাহরণ স্বরূপ:

import os

def my_lock(f):
    if os.name == "posix":
        # Unix or OS X specific locking here
    elif os.name == "nt":
        # Windows specific locking here
    else:
        print "Unknown operating system, lock unavailable"

7
আপনি এটি ইতিমধ্যে জানতে পারেন, তবে চলমান প্ল্যাটফর্মের তথ্য পাওয়ার জন্য প্ল্যাটফর্ম মডিউলটি উপলব্ধ। platform.system ()। docs.python.org/library/platform.html
monkut

2

আমি এইরকম পরিস্থিতিতে কাজ করছি যেখানে একই ডিরেক্টরি / ফোল্ডার এবং লগিংয়ের ত্রুটিগুলির মধ্যে থেকে একই প্রোগ্রামের একাধিক অনুলিপিগুলি চালিত করি। আমার পদ্ধতির লগ ফাইলটি খোলার আগে ডিস্কে একটি "লক ফাইল" লেখার ছিল। প্রোগ্রামটি এগিয়ে যাওয়ার আগে "লক ফাইল" উপস্থিতি যাচাই করে এবং "লক ফাইল" উপস্থিত থাকলে এটির পরিবর্তনের জন্য অপেক্ষা করে।

কোডটি এখানে:

def errlogger(error):

    while True:
        if not exists('errloglock'):
            lock = open('errloglock', 'w')
            if exists('errorlog'): log = open('errorlog', 'a')
            else: log = open('errorlog', 'w')
            log.write(str(datetime.utcnow())[0:-7] + ' ' + error + '\n')
            log.close()
            remove('errloglock')
            return
        else:
            check = stat('errloglock')
            if time() - check.st_ctime > 0.01: remove('errloglock')
            print('waiting my turn')

সম্পাদনা করুন --- উপরে বাসি লকগুলি সম্পর্কে কিছু মন্তব্য করার পরে আমি "লক ফাইল" -এর বাসির জন্য একটি চেক যুক্ত করার জন্য কোডটি সম্পাদনা করেছি। আমার সিস্টেমে এই ফাংশনটির কয়েক হাজার পুনরাবৃত্তি করার সময় দেওয়া হয়েছে এবং ঠিক আগে থেকে 0.002066 ... সেকেন্ডে গড়:

lock = open('errloglock', 'w')

ঠিক পরে:

remove('errloglock')

সুতরাং আমি বুঝতে পেরেছি যে বাসিটি নির্দেশ করতে এবং সমস্যার পরিস্থিতি পর্যবেক্ষণ করতে আমি এই পরিমাণটি 5 গুণ দিয়ে শুরু করব।

এছাড়াও, সময়টি নিয়ে কাজ করার সময় আমি বুঝতে পেরেছিলাম যে আমার একটি কোড রয়েছে যা সত্যই প্রয়োজনীয় ছিল না:

lock.close()

যা আমি অবিলম্বে প্রকাশ্য বিবৃতিটি অনুসরণ করেছি, তাই আমি এই সম্পাদনাটিতে এটি সরিয়েছি।


2

উপর যোগ করতে ইভান Fossmark এর উত্তর , এখানে কিভাবে ব্যবহার করতে একটি উদাহরণ filelock :

from filelock import FileLock

lockfile = r"c:\scr.txt"
lock = FileLock(lockfile + ".lock")
with lock:
    file = open(path, "w")
    file.write("123")
    file.close()

with lock:ব্লকের মধ্যে থাকা কোনও কোড থ্রেড-সেফ, অর্থাত অন্য ফাইলের অ্যাক্সেস পাওয়ার আগে এটি শেষ হয়ে যাবে।


1

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

আমার ওয়ার্কিং কোডটি এখানে:

from lockfile import LockFile
lock = LockFile(lock_file_path)
status = ""
if not lock.is_locked():
    lock.acquire()
    status = lock.path + ' is locked.'
    print status
else:
    status = lock.path + " is already locked."
    print status

return status

0

গ্রিজল্ড-পাইথন থেকে আমি একটি সহজ এবং কাজ (!) বাস্তবায়ন পেয়েছি।

সাধারণ ব্যবহারের জন্য os.open (..., O_EXCL) + os.close () উইন্ডোতে কাজ করে না।


4
O_EXCL বিকল্পটি লক সম্পর্কিত নয়
সের্গেই

0

আপনি পাইলকারকে খুব দরকারী বলে মনে করতে পারেন । এটি কোনও ফাইল লক করতে বা সাধারণভাবে লক করার পদ্ধতিতে ব্যবহৃত হতে পারে এবং একাধিক পাইথন প্রক্রিয়া থেকে একবারে অ্যাক্সেস করা যায়।

আপনি যদি কেবল কোনও ফাইল লক করতে চান তবে এটি কীভাবে কাজ করে তা এখানে:

import uuid
from pylocker import Locker

#  create a unique lock pass. This can be any string.
lpass = str(uuid.uuid1())

# create locker instance.
FL = Locker(filePath='myfile.txt', lockPass=lpass, mode='w')

# aquire the lock
with FL as r:
    # get the result
    acquired, code, fd  = r

    # check if aquired.
    if fd is not None:
        print fd
        fd.write("I have succesfuly aquired the lock !")

# no need to release anything or to close the file descriptor, 
# with statement takes care of that. let's print fd and verify that.
print fd
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.