একটি ফাংশন কল সময় শেষ


300

আমি পাইথনে একটি ফাংশন বলছি যা আমি জানি যা স্টপ হতে পারে এবং আমাকে স্ক্রিপ্টটি পুনরায় চালু করতে বাধ্য করতে পারে।

আমি কীভাবে এই ফাংশনটিকে কল করব বা এটিকে কীভাবে लपेटবো যাতে এটি যদি 5 সেকেন্ডের বেশি সময় নেয় তবে স্ক্রিপ্টটি এটি বাতিল করে এবং অন্য কিছু করে?

উত্তর:


227

আপনি যদি ইউনিক্সে চালাচ্ছেন তবে আপনি সিগন্যাল প্যাকেজটি ব্যবহার করতে পারেন :

In [1]: import signal

# Register an handler for the timeout
In [2]: def handler(signum, frame):
   ...:     print("Forever is over!")
   ...:     raise Exception("end of time")
   ...: 

# This function *may* run for an indetermined time...
In [3]: def loop_forever():
   ...:     import time
   ...:     while 1:
   ...:         print("sec")
   ...:         time.sleep(1)
   ...:         
   ...:         

# Register the signal function handler
In [4]: signal.signal(signal.SIGALRM, handler)
Out[4]: 0

# Define a timeout for your function
In [5]: signal.alarm(10)
Out[5]: 0

In [6]: try:
   ...:     loop_forever()
   ...: except Exception, exc: 
   ...:     print(exc)
   ....: 
sec
sec
sec
sec
sec
sec
sec
sec
Forever is over!
end of time

# Cancel the timer if the function returned before timeout
# (ok, mine won't but yours maybe will :)
In [7]: signal.alarm(0)
Out[7]: 0

কল করার 10 সেকেন্ড পরে alarm.alarm(10), হ্যান্ডলারটি কল করা হয়। এটি একটি ব্যতিক্রম উত্থাপন করে যা আপনি নিয়মিত পাইথন কোড থেকে বিরত রাখতে পারেন।

এই মডিউলটি থ্রেডগুলির সাথে ভাল খেলছে না (তবে তারপরে কে করবে?)

নোট করুন যেহেতু সময়সীমা শেষ হওয়ার পরে আমরা একটি ব্যতিক্রম উত্থাপন করি, সুতরাং এটি ফাংশনের অভ্যন্তরে ধরা পড়ে এবং উপেক্ষা করা যেতে পারে, যেমন একটির ফাংশনের উদাহরণ:

def loop_forever():
    while 1:
        print('sec')
        try:
            time.sleep(10)
        except:
            continue

5
আমি পাইথন 2.5.4 ব্যবহার করি। (Signal.SIGALRM, হ্যান্ডলার) AttributeError func signal.signal ফাইল "aa.py", লাইন 85,: যেমন একটি ত্রুটি আছে: ট্রেসব্যাক (সাম্প্রতিকতম কল শেষ) 'মডিউল' অবজেক্ট কোন অ্যাট্রিবিউট 'SIGALRM' হয়েছে
flypen

11
@ ফ্লাইপেন কারণ signal.alarmএবং SIGALRMউইন্ডোজ প্ল্যাটফর্মগুলিতে সম্পর্কিতগুলি উপলভ্য নয়।
ডাবল এএ

2
যদি প্রচুর প্রক্রিয়া হয়, এবং প্রতিটি কল signal.signal--- তারা সবাই ঠিকঠাকভাবে কাজ করবে? প্রতিটি signal.signalকল কি "সমবর্তী" একটিকে বাতিল করবেন না ?
ব্রাউনিয়ান

1
এটি কোনও সি এক্সটেনশান সহ ব্যবহার করতে ইচ্ছুকদের জন্য সতর্কতা: সি ফাংশনটি পাইথন ইন্টারপ্রেটারে নিয়ন্ত্রণ না ফেরানো পর্যন্ত পাইথন সিগন্যাল হ্যান্ডলার কল করা হবে না। : এই ব্যবহারের ক্ষেত্রে জন্য ব্যবহার ATOzTOA এর উত্তর stackoverflow.com/a/14924210/1286628
wkschwartz

13
আমি থ্রেড সম্পর্কে সতর্কতা দ্বিতীয়। সংকেত.এলার্ম কেবলমাত্র মূল থ্রেডে কাজ করে। আমি এটি জ্যাঙ্গো ভিউগুলিতে ব্যবহার করার চেষ্টা করেছি - কেবলমাত্র মূল থ্রেডের সাথে মৌখিকতায় তাত্ক্ষণিকভাবে ব্যর্থ।
জেএল পেয়ারেট

154

আপনি multiprocessing.Processঠিক এটি করতে ব্যবহার করতে পারেন ।

কোড

import multiprocessing
import time

# bar
def bar():
    for i in range(100):
        print "Tick"
        time.sleep(1)

if __name__ == '__main__':
    # Start bar as a process
    p = multiprocessing.Process(target=bar)
    p.start()

    # Wait for 10 seconds or until process finishes
    p.join(10)

    # If thread is still active
    if p.is_alive():
        print "running... let's kill it..."

        # Terminate
        p.terminate()
        p.join()

36
আমি কীভাবে লক্ষ্য পদ্ধতির রিটার্ন মান পেতে পারি?
খারাপ_কিপয়েন্ট

4
কল করা ফাংশন যদি আই / ও ব্লকের সাথে আটকে যায় তবে এটি কাজ করবে বলে মনে হচ্ছে না।
sudo

4
@bad_keypoints এই উত্তরটি দেখুন: stackoverflow.com/a/10415215/1384471 মূলত, আপনি একটি তালিকা যে বরাবর আপনি মধ্যে উত্তর করা পাস।
পিটার

1
@ সুডো তারপর অপসারণ করুন join()। এটি আপনার এক্স সংখ্যা সহকারী সাবপ্রসেসগুলি চালিয়ে যাচ্ছে যতক্ষণ না তাদের কাজ শেষ করে দেয় বা সংজ্ঞায়িত পরিমাণ join(10)। কেস আপনি 10 টি প্রক্রিয়ার জন্য ব্লকিং আই / ও রেখেছেন, জয়েন (10) ব্যবহার করে আপনি তাদের প্রতিটি সেট প্রক্রিয়া শুরু হওয়ার জন্য সর্বোচ্চ 10 অপেক্ষা করার জন্য সেট করেছেন। এই উদাহরণস্বরূপ স্ট্যাকওভারফ্লো . com/a/27420072/2480481 এর মতো ডেমন পতাকা ব্যবহার করুন । অবশ্যই আপনি daemon=Trueসরাসরি কাজ করতে পতাকা পাস করতে পারেন multiprocessing.Process()
এম

2
কমপক্ষে আমার উদ্দেশ্যগুলির জন্য @ATOTTAA এই সমাধানটি নিয়ে সমস্যাটি হ'ল এটি সম্ভবত বাচ্চাদের নিজের পরে পরিষ্কার করার অনুমতি দেয় না। সমাপ্ত ফাংশনের ডকুমেন্টেশন থেকেterminate() ... Note that exit handlers and finally clauses, etc., will not be executed. Note that descendant processes of the process will not be terminated – they will simply become orphaned.
abalcerek

78

আমি কীভাবে এই ফাংশনটিকে কল করব বা এটিকে আমি কীভাবে মুড়িয়ে দেব যাতে স্ক্রিপ্টটি এটি বাতিল করতে 5 সেকেন্ডের বেশি সময় নেয়?

আমি একটি পোস্ট সারকথা যে সমাধান এই প্রশ্নের / একটি প্রসাধক এবং সঙ্গে সমস্যা threading.Timer। এখানে এটি একটি ভাঙ্গন সঙ্গে।

সামঞ্জস্যের জন্য আমদানি এবং সেটআপ

এটি পাইথন 2 এবং 3 দিয়ে পরীক্ষা করা হয়েছিল এটি ইউনিক্স / লিনাক্স এবং উইন্ডোজের অধীনেও কাজ করা উচিত।

প্রথমে আমদানি। পাইথন সংস্করণ নির্বিশেষে কোডটিকে ধারাবাহিক রাখার এই প্রচেষ্টা:

from __future__ import print_function
import sys
import threading
from time import sleep
try:
    import thread
except ImportError:
    import _thread as thread

সংস্করণ স্বাধীন কোড ব্যবহার করুন:

try:
    range, _print = xrange, print
    def print(*args, **kwargs): 
        flush = kwargs.pop('flush', False)
        _print(*args, **kwargs)
        if flush:
            kwargs.get('file', sys.stdout).flush()            
except NameError:
    pass

এখন আমরা স্ট্যান্ডার্ড লাইব্রেরি থেকে আমাদের কার্যকারিতা আমদানি করেছি।

exit_after প্রসাধক

main()চাইল্ড থ্রেড থেকে শেষ করতে আমাদের একটি ক্রিয়া প্রয়োজন :

def quit_function(fn_name):
    # print to stderr, unbuffered in Python 2.
    print('{0} took too long'.format(fn_name), file=sys.stderr)
    sys.stderr.flush() # Python 3 stderr is likely buffered.
    thread.interrupt_main() # raises KeyboardInterrupt

এবং এখানে নিজেই সাজসজ্জা রয়েছে:

def exit_after(s):
    '''
    use as decorator to exit process if 
    function takes longer than s seconds
    '''
    def outer(fn):
        def inner(*args, **kwargs):
            timer = threading.Timer(s, quit_function, args=[fn.__name__])
            timer.start()
            try:
                result = fn(*args, **kwargs)
            finally:
                timer.cancel()
            return result
        return inner
    return outer

ব্যবহার

এবং এখানে ব্যবহার যা 5 সেকেন্ড পরে প্রস্থান করার বিষয়ে আপনার প্রশ্নের সরাসরি উত্তর দেয় !:

@exit_after(5)
def countdown(n):
    print('countdown started', flush=True)
    for i in range(n, -1, -1):
        print(i, end=', ', flush=True)
        sleep(1)
    print('countdown finished')

ডেমো:

>>> countdown(3)
countdown started
3, 2, 1, 0, countdown finished
>>> countdown(10)
countdown started
10, 9, 8, 7, 6, countdown took too long
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 11, in inner
  File "<stdin>", line 6, in countdown
KeyboardInterrupt

দ্বিতীয় ফাংশন কল শেষ হবে না, পরিবর্তে প্রক্রিয়াটি একটি ট্রেসব্যাক দিয়ে প্রস্থান করা উচিত!

KeyboardInterrupt সর্বদা একটি ঘুমানোর থ্রেড থামায় না

নোট করুন যে উইন্ডোজটির পাইথন 2 এ, কোনও কিবোর্ড বাধা দিয়ে ঘুম সবসময় ব্যহত হবে না, যেমন:

@exit_after(1)
def sleep10():
    sleep(10)
    print('slept 10 seconds')

>>> sleep10()
sleep10 took too long         # Note that it hangs here about 9 more seconds
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 11, in inner
  File "<stdin>", line 3, in sleep10
KeyboardInterrupt

কিংবা যদি না তা স্পষ্টভাবে চেক এক্সটেনশন চলমান বিঘ্ন কোডে সম্ভবত এটা PyErr_CheckSignals()দেখতে Cython, পাইথন এবং KeyboardInterrupt উপেক্ষিত

আমি কোনও সেকেন্ডের চেয়েও বেশি সুতোর ঘুম এড়াতে পারব না - এটি প্রসেসরের সময়কালের।

আমি কীভাবে এই ফাংশনটিকে কল করব বা এটিকে আমি কীভাবে মুড়িয়ে দেব যাতে এটি যদি 5 সেকেন্ডের বেশি সময় নেয় তবে স্ক্রিপ্টটি এটি বাতিল করে এবং অন্য কিছু করে?

এটি ধরতে এবং অন্য কিছু করতে, আপনি কীবোর্ড ইন্টারটারপট ধরতে পারেন।

>>> try:
...     countdown(10)
... except KeyboardInterrupt:
...     print('do something else')
... 
countdown started
10, 9, 8, 7, 6, countdown took too long
do something else

আমি আপনার পুরো পোস্টটি এখনও পড়িনি, তবে আমি কেবল ভাবছিলাম: ফ্লাশ 0 হলে কী হবে? এটি নীচে যদি বিবৃতিতে মিথ্যা হিসাবে ব্যাখ্যা করা হবে, ঠিক?
কোনেনরাদ ভ্যান ডুইন

2
আমাকে কেন ফোন করতে হবে thread.interrupt_main(), কেন আমি সরাসরি একটি ব্যতিক্রম বাড়াতে পারি না?
অনির্বাণ নাগ 'tintinmj'

এর multiprocessing.connection.Clientসাথে মোড়কে নেওয়ার কোনও চিন্তা ? - সমাধান করার চেষ্টা করছেন: স্ট্যাকওভারফ্লো.com
ডাব্লিউইআই

51

আমার একটি আলাদা প্রস্তাব আছে যা একটি খাঁটি ফাংশন (থ্রেডিংয়ের পরামর্শের মতো একই এপিআই সহ) এবং ভাল কাজ করছে বলে মনে হচ্ছে (এই থ্রেডের পরামর্শের ভিত্তিতে)

def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):
    import signal

    class TimeoutError(Exception):
        pass

    def handler(signum, frame):
        raise TimeoutError()

    # set the timeout handler
    signal.signal(signal.SIGALRM, handler) 
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
    finally:
        signal.alarm(0)

    return result

3
আপনার মূল সংকেত হ্যান্ডলারটি পুনরুদ্ধার করা উচিত। স্ট্যাকওভারফ্লো
প্রশ্নগুলি / 492519/…

9
আরও একটি নোট: ইউনিক্স সিগন্যাল পদ্ধতিটি কেবলমাত্র যদি আপনি এটিকে মূল থ্রেডটিতে প্রয়োগ করছেন তবে কাজ করে। এটি একটি সাব-থ্রেডে প্রয়োগ করা একটি ব্যতিক্রম ছোঁড়ে এবং কাজ করবে না।
মার্টিন কনেকেনি

12
এটি সেরা সমাধান নয় কারণ এটি কেবল লিনাক্সের জন্যই কাজ করে।
সর্বোচ্চ 10

17
সর্বাধিক, সত্য নয় - কোনও পসিক্স-সম্মতিযুক্ত ইউনিক্সে কাজ করে। আমি মনে করি আপনার মন্তব্যটি আরও নির্ভুল হওয়া উচিত, উইন্ডোজটিতে কাজ করে না।
ক্রিস জনসন

6
আপনার খালি ডিকটিতে কাওয়ারগুলি সেট করা এড়ানো উচিত। একটি সাধারণ পাইথন গেটচা হ'ল ফাংশনগুলিতে ডিফল্ট যুক্তিগুলি পরিবর্তনযোগ্য। যাতে অভিধানটি সমস্ত কলগুলিতে ভাগ করা হবে timeout। ডিফল্টটিতে Noneফাংশনটির প্রথম লাইনে সেট করা আরও ভাল kwargs = kwargs or {}। আরগস ঠিক আছে কারণ টিপলস পরিবর্তনীয় নয়।
স্কটম্রোগোস্কি

31

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

import multiprocessing.pool
import functools

def timeout(max_timeout):
    """Timeout decorator, parameter in seconds."""
    def timeout_decorator(item):
        """Wrap the original function."""
        @functools.wraps(item)
        def func_wrapper(*args, **kwargs):
            """Closure for function."""
            pool = multiprocessing.pool.ThreadPool(processes=1)
            async_result = pool.apply_async(item, args, kwargs)
            # raises a TimeoutError if execution exceeds max_timeout
            return async_result.get(max_timeout)
        return func_wrapper
    return timeout_decorator

তারপরে এটি কোনও পরীক্ষা বা আপনার পছন্দসই কোনও কার্যের সময় শেষ করার মতো সহজ as

@timeout(5.0)  # if execution takes longer than 5 seconds, raise a TimeoutError
def test_base_regression(self):
    ...

14
সময়সীমাটি শেষ হওয়ার পরে এটি ফাংশনটি শেষ না করায় সাবধান!
সিলভাইন

নোট করুন যে উইন্ডোজে এটি পুরোপুরি নতুন প্রক্রিয়া তৈরি করেছে - যা সময়সীমার সময় নেমে আসবে, সম্ভবত নির্ভরতাগুলি সেট আপ করতে দীর্ঘ সময় নিলে।
অ্যারন হল

1
হ্যাঁ, এর জন্য কিছু টুইট করা দরকার। এটি থ্রেডকে চিরতরে যেতে দেয়।
সুডো

2
আইডি কে যদি এটি সর্বোত্তম উপায় তবে আপনি Exceptionথানায় pool.close()সর্বদা মারা যাওয়ার বিষয়টি নিশ্চিত করার জন্য ফানক_রাপ্পারের ভিতরে / ধরার চেষ্টা করতে পারেন এবং ক্যাচের পরেও করতে পারেন what তারপরে আপনি নিক্ষেপ করতে পারেন TimeoutErrorবা আপনি যা চান তা পারেন। আমার জন্য কাজ করে বলে মনে হয়।
সুডো

2
এটি ব্যবহারযোগ্য, তবে একবার আমি এটি বহুবার করে ফেললে আমি পাই RuntimeError: can't start new thread। আমি যদি এটিকে উপেক্ষা করি বা এটির কাছাকাছি যাওয়ার জন্য আমি আরও কিছু করতে পারি তবে এটি এখনও কাজ করবে? আগাম ধন্যবাদ!
বেঞ্জি

19

দ্য stopitপ্যাকেজ, pypi পাওয়া, ভাল সময় সমাপ্ত হ্যান্ডেল বলে মনে হয়।

আমি পছন্দ করি @stopit.threading_timeoutable সাজসজ্জার , যা timeoutসজ্জিত ফাংশনে একটি প্যারামিটার যুক্ত করে, যা আপনি প্রত্যাশা করেন এটি করে, এটি ফাংশনটি বন্ধ করে দেয়।

এটি পাইপিতে দেখুন: https://pypi.python.org/pypi/stopit


1
এটি খুব সহজ এবং থ্রেড-নিরাপদ! ধন্যবাদ এবং প্লাস ওয়ান! এটি এখন পর্যন্ত আমি খুঁজে পেয়েছি সেরা বিকল্পটি এবং গ্রহণযোগ্য উত্তরের চেয়েও ভাল !!
ইয়াহিয়া

গ্রন্থাগারের দাবি, কিছু কার্যকারিতা উইন্ডোজে কাজ করে না।
স্টিফান সিমিক

16

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

from concurrent.futures import ProcessPoolExecutor

# Warning: this does not terminate function if timeout
def timeout_five(fnc, *args, **kwargs):
    with ProcessPoolExecutor() as p:
        f = p.submit(fnc, *args, **kwargs)
        return f.result(timeout=5)

পড়তে এবং বজায় রাখতে খুব সহজ simple

আমরা একটি পুল তৈরি করি, একটি একক প্রক্রিয়া জমা দিন এবং তারপরে একটি টাইমআউটআরারের উত্থাপনের আগে 5 সেকেন্ড পর্যন্ত অপেক্ষা করুন যা আপনার প্রয়োজনে আপনাকে ধরতে এবং পরিচালনা করতে পারে।

অজগর 3.2+ নেটিভ এবং 2.7 (পিপ ইনস্টল ফিউচার) এ ব্যাকপোর্ট করা হয়েছে।

থ্রেড এবং প্রক্রিয়াগুলির মধ্যে স্যুইচিং প্রতিস্থাপন হিসাবে হিসাবে সহজ ProcessPoolExecutorসঙ্গে ThreadPoolExecutor

সময়সীমার সময় যদি আপনি প্রক্রিয়াটি শেষ করতে চান তবে আমি নুড়িটি অনুসন্ধান করার পরামর্শ দেব ।


2
"সতর্কতা: সময়সীমা শেষ হলে" এটি ফাংশনটি শেষ করে না?
স্কট স্টাফোর্ড

5
@ স্কট স্টাফর্ড প্রক্রিয়াগুলি / থ্রেডগুলি কেবলমাত্র একটি টাইমআউটআরার উত্থাপিত হওয়ার কারণে শেষ হয় না। সুতরাং প্রক্রিয়া বা থ্রেড এখনও সম্পূর্ণরূপে চালানোর চেষ্টা করবে এবং স্বয়ংক্রিয়ভাবে আপনার সময়সীমাতে আপনাকে নিয়ন্ত্রণ ফিরিয়ে দেবে না।
ব্রায়ান

এটি কি আমাকে মধ্যবর্তী সময়ে যে কোনও ফলাফল সংরক্ষণ করতে দেবে? উদাহরণস্বরূপ, যদি আমার পুনরাবৃত্ত ফাংশন থাকে যা আমি টাইমআউট 5 তে নির্ধারণ করি এবং সেই সময়ে আমার আংশিক ফলাফল হয়, সময়সীমা শেষ হওয়ার পরে আমি আংশিক ফলাফলগুলি ফাংশনটি কীভাবে লিখব?
SumNeuron

আমি ঠিক এটি ব্যবহার করছি, তবে আমার 1000 টি কাজ রয়েছে, প্রত্যেকের সময়সীমা শেষ হওয়ার 5 সেকেন্ড আগে অনুমোদিত allowed আমার সমস্যাটি হ'ল কোরগুলি এমন কাজগুলিতে আটকে যায় যা কখনই শেষ হয় না কারণ সময়সীমাটি কেবলমাত্র পৃথক কার্যগুলিতে নয় মোট কাজগুলিতে প্রয়োগ করা হয়। একযোগে.ফিউচারগুলি এই আফাইকটির কোনও সমাধান সরবরাহ করে না।
বাসটিয়ান

11

গ্রেট, সহজে ব্যবহার করা যায় এবং নির্ভরযোগ্য PyPi প্রকল্পের মেয়াদ শেষ হওয়ার সময়সীমা-প্রসাধক ( https://pypi.org/project/timeout-decorator/ )

ইনস্টলেশন :

pip install timeout-decorator

ব্যবহার :

import time
import timeout_decorator

@timeout_decorator.timeout(5)
def mytest():
    print "Start"
    for i in range(1,10):
        time.sleep(1)
        print "%d seconds have passed" % i

if __name__ == '__main__':
    mytest()

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

@Wysuper লাইবটিতে অপারেশনগুলির 2 টি পদ্ধতি রয়েছে: নতুন থ্রেড বা একটি নতুন সাবপ্রসেস খুলুন (যা থ্রেডকে নিরাপদ বলে মনে করেন)
গিল

6

আমি মোড়কের_আরআউটআউট_ডেকোরেটর

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

উইন্ডোজের অধীনে কোনও প্রক্রিয়া উত্সাহিত করার জন্য, এটি বাছাইযোগ্য হওয়া দরকার - এবং অনেকগুলি সজ্জিত ফাংশন বা শ্রেণিবদ্ধ পদ্ধতি নয়।

সুতরাং আপনাকে ডিল এবং মাল্টিপ্রসেসের মতো আরও ভাল পিকার ব্যবহার করতে হবে (আচার এবং মাল্টিপ্রসেসিং নয়) - আপনি প্রসেসপুলএক্সেসিটার কেন ব্যবহার করতে পারবেন না (বা কেবলমাত্র সীমিত কার্যকারিতা সহ)।

সময়সীমা নিজেই - আপনার সময়সীমাটির অর্থ কী তা আপনাকে নির্ধারণ করতে হবে - কারণ উইন্ডোজটিতে প্রক্রিয়াটি উত্সাহিত করতে যথেষ্ট (এবং নির্ধারণযোগ্য নয়) সময় লাগবে। সংক্ষিপ্ত সময়সীমা এ জটিল হতে পারে। ধরে নেওয়া যাক, প্রসারণের প্রক্রিয়াটি প্রায় 0.5 সেকেন্ড সময় নেয় (সহজেই !!!)। আপনি যদি 0.2 সেকেন্ডের সময়সীমা দেয় তবে কি হবে? ০.০ + ০.২ সেকেন্ড পরে ফাংশনটি শেষ করা উচিত (সুতরাং পদ্ধতিটি 0.2 সেকেন্ডের জন্য চালানো যাক)? বা কল করা প্রক্রিয়াটি 0.2 সেকেন্ড পরে শেষ হওয়া উচিত (সেক্ষেত্রে সজ্জিত ফাংশনটি সবসময়ই শেষ হয়ে যাবে, কারণ সেই সময়ে এটি প্রসারিত হয় না)?

এছাড়াও নেস্টেড সাজসজ্জাগুলি বাজে হতে পারে এবং আপনি সাবস্ট্র্রিডে সিগন্যাল ব্যবহার করতে পারবেন না। আপনি যদি সত্যিকারের সার্বজনীন, ক্রস-প্ল্যাটফর্ম সজ্জা তৈরি করতে চান তবে এই সমস্ত বিষয় বিবেচনায় নেওয়া প্রয়োজন (এবং পরীক্ষিত)।

অন্যান্য সমস্যাগুলি কলারের কাছে ফিরে ব্যতিক্রমগুলি পাশ করার পাশাপাশি লগিংয়ের সমস্যাগুলি (যদি সজ্জিত ফাংশনে ব্যবহৃত হয় - অন্য কোনও প্রক্রিয়াতে ফাইলগুলিতে লগ ইন করা সমর্থনযোগ্য নয়)

আমি সমস্ত প্রান্তের কেসগুলি কভার করার চেষ্টা করেছি, আপনি প্যাকেজ ptেকে দিতে পারেন pt

@ অ্যালেক্সিস এগারমন্ট - দুর্ভাগ্যক্রমে আমার মন্তব্য করার মতো পর্যাপ্ত পয়েন্ট নেই - সম্ভবত অন্য কেউ আপনাকে অবহিত করতে পারে - আমি মনে করি আমি আপনার আমদানির সমস্যাটি সমাধান করেছি।


3

timeout-decoratorউইন্ডোজ সিস্টেমে যেমন কাজ করে না, উইন্ডোজগুলি signalভাল সমর্থন করে না ।

আপনি উইন্ডোজ সিস্টেমে টাইমআউট-ডেকোরেটর ব্যবহার করেন তবে নিম্নলিখিতগুলি পাবেন

AttributeError: module 'signal' has no attribute 'SIGALRM'

কেউ কেউ ব্যবহার করার পরামর্শ দিলেন use_signals=False কিন্তু আমার পক্ষে কাজ করেননি।

লেখক @bitranox নিম্নলিখিত প্যাকেজটি তৈরি করেছেন:

pip install https://github.com/bitranox/wrapt-timeout-decorator/archive/master.zip

কোড নমুনা:

import time
from wrapt_timeout_decorator import *

@timeout(5)
def mytest(message):
    print(message)
    for i in range(1,10):
        time.sleep(1)
        print('{} seconds have passed'.format(i))

def main():
    mytest('starting')


if __name__ == '__main__':
    main()

নিম্নলিখিত ব্যতিক্রম দেয়:

TimeoutError: Function mytest timed out after 5 seconds

এই শব্দটি খুব সুন্দর সমাধানের মতো। আশ্চর্যজনকভাবে, লাইনটি from wrapt_timeout_decorator import * আমার অন্যান্য আমদানিগুলির কিছু মারতে বলে মনে হচ্ছে। উদাহরণ হিসেবে বলা যায় আমি পেতে ModuleNotFoundError: No module named 'google.appengine', কিন্তু আমি এই ত্রুটি পাবেন না যদি আমি আমদানি না wrapt_timeout_decorator না
অ্যালেক্সিস Eggermont

@ অ্যালেক্সিসএগারমন্ট আমি অ্যাপেনজিন দিয়ে এটি ব্যবহার করতে চলেছিলাম ... তাই আমি যদি খুব ত্রুটিযুক্ত থাকি তবে এই ত্রুটিটি যদি অব্যাহত থাকে?
পাসক্যালভিকুটেন

2

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

import signal

def timeout(signum, frame):
    raise myException

#this is an infinite loop, never ending under normal circumstances
def main():
    print 'Starting Main ',
    while 1:
        print 'in main ',

#SIGALRM is only usable on a unix platform
signal.signal(signal.SIGALRM, timeout)

#change 5 to however many seconds you need
signal.alarm(5)

try:
    main()
except myException:
    print "whoops"

1
একটি নির্দিষ্ট ব্যতিক্রম চয়ন করা এবং এটি কেবল ধরা ভাল would বিরল try: ... except: ...সবসময় একটি খারাপ ধারণা।
সরান

আমি তোমার সাথে একমত হই
এআর

2
#!/usr/bin/python2
import sys, subprocess, threading
proc = subprocess.Popen(sys.argv[2:])
timer = threading.Timer(float(sys.argv[1]), proc.terminate)
timer.start()
proc.wait()
timer.cancel()
exit(proc.returncode)

7
যদিও এই কোডটি প্রশ্নের উত্তর দিতে পারে, কীভাবে এবং / বা কেন এটি সমস্যার সমাধান করে তা সম্পর্কিত অতিরিক্ত প্রসঙ্গ সরবরাহ করলে উত্তরটির দীর্ঘমেয়াদী মান উন্নত হবে
ড্যান কর্নিলিস্কু

1

আমি জন্য প্রয়োজন ছিল nestable সুবিধানুযায়ী বিঘ্নিত (SIGALARM ব্যবহার করতে পারবেন না, যা) যে time.sleep দ্বারা অবরুদ্ধ করা হবে না (যা থ্রেড ভিত্তিক পদ্ধতির ব্যবহার করতে পারবেন না)। আমি এখান থেকে কোড অনুলিপি এবং হালকাভাবে সংশোধন করে শেষ করেছি: http://code.activestate.com/recips/577600-queue-for-managing-m Multiple-sigalrm-alarms-concurr/

কোড নিজেই:

#!/usr/bin/python

# lightly modified version of http://code.activestate.com/recipes/577600-queue-for-managing-multiple-sigalrm-alarms-concurr/


"""alarm.py: Permits multiple SIGALRM events to be queued.

Uses a `heapq` to store the objects to be called when an alarm signal is
raised, so that the next alarm is always at the top of the heap.
"""

import heapq
import signal
from time import time

__version__ = '$Revision: 2539 $'.split()[1]

alarmlist = []

__new_alarm = lambda t, f, a, k: (t + time(), f, a, k)
__next_alarm = lambda: int(round(alarmlist[0][0] - time())) if alarmlist else None
__set_alarm = lambda: signal.alarm(max(__next_alarm(), 1))


class TimeoutError(Exception):
    def __init__(self, message, id_=None):
        self.message = message
        self.id_ = id_


class Timeout:
    ''' id_ allows for nested timeouts. '''
    def __init__(self, id_=None, seconds=1, error_message='Timeout'):
        self.seconds = seconds
        self.error_message = error_message
        self.id_ = id_
    def handle_timeout(self):
        raise TimeoutError(self.error_message, self.id_)
    def __enter__(self):
        self.this_alarm = alarm(self.seconds, self.handle_timeout)
    def __exit__(self, type, value, traceback):
        try:
            cancel(self.this_alarm) 
        except ValueError:
            pass


def __clear_alarm():
    """Clear an existing alarm.

    If the alarm signal was set to a callable other than our own, queue the
    previous alarm settings.
    """
    oldsec = signal.alarm(0)
    oldfunc = signal.signal(signal.SIGALRM, __alarm_handler)
    if oldsec > 0 and oldfunc != __alarm_handler:
        heapq.heappush(alarmlist, (__new_alarm(oldsec, oldfunc, [], {})))


def __alarm_handler(*zargs):
    """Handle an alarm by calling any due heap entries and resetting the alarm.

    Note that multiple heap entries might get called, especially if calling an
    entry takes a lot of time.
    """
    try:
        nextt = __next_alarm()
        while nextt is not None and nextt <= 0:
            (tm, func, args, keys) = heapq.heappop(alarmlist)
            func(*args, **keys)
            nextt = __next_alarm()
    finally:
        if alarmlist: __set_alarm()


def alarm(sec, func, *args, **keys):
    """Set an alarm.

    When the alarm is raised in `sec` seconds, the handler will call `func`,
    passing `args` and `keys`. Return the heap entry (which is just a big
    tuple), so that it can be cancelled by calling `cancel()`.
    """
    __clear_alarm()
    try:
        newalarm = __new_alarm(sec, func, args, keys)
        heapq.heappush(alarmlist, newalarm)
        return newalarm
    finally:
        __set_alarm()


def cancel(alarm):
    """Cancel an alarm by passing the heap entry returned by `alarm()`.

    It is an error to try to cancel an alarm which has already occurred.
    """
    __clear_alarm()
    try:
        alarmlist.remove(alarm)
        heapq.heapify(alarmlist)
    finally:
        if alarmlist: __set_alarm()

এবং ব্যবহারের উদাহরণ:

import alarm
from time import sleep

try:
    with alarm.Timeout(id_='a', seconds=5):
        try:
            with alarm.Timeout(id_='b', seconds=2):
                sleep(3)
        except alarm.TimeoutError as e:
            print 'raised', e.id_
        sleep(30)
except alarm.TimeoutError as e:
    print 'raised', e.id_
else:
    print 'nope.'

এটি সিগন্যালও ব্যবহার করে তাই কোনও থ্রেড থেকে ডাকা হলে কাজ করবে না।
garg10may

0

প্রদত্ত থ্রেড-ভিত্তিক সমাধানের জন্য এখানে সামান্য উন্নতি দেওয়া হয়েছে।

নীচের কোডটি ব্যতিক্রমগুলি সমর্থন করে :

def runFunctionCatchExceptions(func, *args, **kwargs):
    try:
        result = func(*args, **kwargs)
    except Exception, message:
        return ["exception", message]

    return ["RESULT", result]


def runFunctionWithTimeout(func, args=(), kwargs={}, timeout_duration=10, default=None):
    import threading
    class InterruptableThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.result = default
        def run(self):
            self.result = runFunctionCatchExceptions(func, *args, **kwargs)
    it = InterruptableThread()
    it.start()
    it.join(timeout_duration)
    if it.isAlive():
        return default

    if it.result[0] == "exception":
        raise it.result[1]

    return it.result[1]

এটি 5 সেকেন্ডের সময়সীমা সহ চালু করা:

result = timeout(remote_calculate, (myarg,), timeout_duration=5)

1
এটি আসল ট্রেসব্যাকটি গোপন করে একটি নতুন ব্যতিক্রম বাড়িয়ে তুলবে। নীচে আমার সংস্করণটি দেখুন ...
মাইথাম

1
এটিও অনিরাপদ, যেন runFunctionCatchExceptions()কিছু পাইথনের মধ্যে জিআইএল প্রাপ্ত ফাংশনগুলিকে ডাকা হয়। যেমন নিম্নলিখিত would না, বা খুব দীর্ঘ সময়ের জন্য, এর বিনিময়ে যদি ফাংশন মধ্যে ডাকলেন eval(2**9999999999**9999999999)। দেখুন stackoverflow.com/questions/22138190/...
Mikko Ohtamaa
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.