Programing

파이썬에서 스케줄러와 같은 Cron을 얻으려면 어떻게해야합니까?

lottogame 2020. 3. 13. 08:15
반응형

파이썬에서 스케줄러와 같은 Cron을 얻으려면 어떻게해야합니까? [닫은]


기능 을 제공 at하고 cron좋아할 파이썬 라이브러리를 찾고 있습니다.

상자에 설치된 도구에 의존하기보다는 순수한 파이썬 솔루션을 원합니다. 이 방법으로 나는 cron이없는 머신에서 실행합니다.

익숙하지 않은 사람들을 위해 cron:

 0 2 * * 7 /usr/bin/run-backup # run the backups at 0200 on Every Sunday
 0 9-17/2 * * 1-5 /usr/bin/purge-temps # run the purge temps command, every 2 hours between 9am and 5pm on Mondays to Fridays.

cron 시간 표현 구문은 덜 중요하지만 이러한 종류의 유연성을 가진 것을 원합니다.

기본적으로이 작업을 수행 할 수있는 작업이 없으면 빌딩 블록에서 이와 같은 작업을 수행 할 수있는 제안이 있으면 감사하겠습니다.

편집 프로세스 시작에 관심이없고 파이썬으로 작성된 "작업"-파이썬 함수에 관심이 있습니다. 필연적으로 나는 이것이 다른 스레드 일 것이라고 생각하지만 다른 프로세스에는 없습니다.

이를 위해 cron 시간 표현의 표현력을 찾고 있지만 Python에서는 찾고 있습니다.

Cron 수년 동안 사용되어 왔지만 가능한 한 휴대하기 위해 노력하고 있습니다. 나는 그 존재에 의존 할 수 없습니다.


간단한 결제 일정을 찾고 있다면 :

import schedule
import time

def job():
    print("I'm working...")

schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)

while 1:
    schedule.run_pending()
    time.sleep(1)

공개 : 나는 그 도서관의 저자입니다.


일반 Python 인수 전달 구문을 사용하여 crontab을 지정할 수 있습니다. 예를 들어, 아래와 같이 Event 클래스를 정의한다고 가정 해보십시오.

from datetime import datetime, timedelta
import time

# Some utility classes / functions first
class AllMatch(set):
    """Universal set - match everything"""
    def __contains__(self, item): return True

allMatch = AllMatch()

def conv_to_set(obj):  # Allow single integer to be provided
    if isinstance(obj, (int,long)):
        return set([obj])  # Single item
    if not isinstance(obj, set):
        obj = set(obj)
    return obj

# The actual Event class
class Event(object):
    def __init__(self, action, min=allMatch, hour=allMatch, 
                       day=allMatch, month=allMatch, dow=allMatch, 
                       args=(), kwargs={}):
        self.mins = conv_to_set(min)
        self.hours= conv_to_set(hour)
        self.days = conv_to_set(day)
        self.months = conv_to_set(month)
        self.dow = conv_to_set(dow)
        self.action = action
        self.args = args
        self.kwargs = kwargs

    def matchtime(self, t):
        """Return True if this event should trigger at the specified datetime"""
        return ((t.minute     in self.mins) and
                (t.hour       in self.hours) and
                (t.day        in self.days) and
                (t.month      in self.months) and
                (t.weekday()  in self.dow))

    def check(self, t):
        if self.matchtime(t):
            self.action(*self.args, **self.kwargs)

(참고 : 철저히 테스트되지 않았습니다)

그런 다음 CronTab을 일반적인 파이썬 구문으로 다음과 같이 지정할 수 있습니다.

c = CronTab(
  Event(perform_backup, 0, 2, dow=6 ),
  Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)

이렇게하면 파이썬의 인수 역학을 최대한 활용할 수 있습니다 (위치 및 키워드 인수를 혼합하고 주 및 월 이름에 기호 이름을 사용할 수 있음)

CronTab 클래스는 분 단위로 잠자고 각 이벤트마다 check ()를 호출하는 것으로 정의됩니다. (아마도 일광 절약 시간 / 시간대에주의해야 할 미묘한 부분이 있습니다). 빠른 구현은 다음과 같습니다.

class CronTab(object):
    def __init__(self, *events):
        self.events = events

    def run(self):
        t=datetime(*datetime.now().timetuple()[:5])
        while 1:
            for e in self.events:
                e.check(t)

            t += timedelta(minutes=1)
            while datetime.now() < t:
                time.sleep((t - datetime.now()).seconds)

주의해야 할 몇 가지 사항 : 파이썬의 주중 / 월은 0으로 색인화되며 (크론과 달리) 해당 범위는 마지막 요소를 제외하므로 "1-5"와 같은 구문은 range (0,5)가됩니다. 즉 [0,1,2, 3,4]. cron 구문을 선호한다면 구문 분석이 너무 어렵지 않아야합니다.


아마도 이것은 질문을 한 후에 만 ​​났을 것입니다. 나는 완전성을 위해 그것을 언급했다고 생각했습니다 : https://apscheduler.readthedocs.org/en/latest/


"... crontab 파일을 읽고 쓰고 Crontab 파일을 자동적이고 간단하게 직접 API를 사용하여 시스템 cron에 액세스하기위한 Crontab 모듈 ..."

http://pypi.python.org/pypi/python-crontab

그리고 파이썬 패키지 인 APScheduler도 있습니다. 이미 작성 및 디버깅되었습니다.

http://packages.python.org/APScheduler/cronschedule.html


필자가 찾은 것 중 하나는 파이썬 sched모듈인데, 이것은 당신이 찾고있는 종류 일 수 있습니다.


위와 다소 비슷하지만 gevent :)를 사용하여 동시에

"""Gevent based crontab implementation"""

from datetime import datetime, timedelta
import gevent

# Some utility classes / functions first
def conv_to_set(obj):
    """Converts to set allowing single integer to be provided"""

    if isinstance(obj, (int, long)):
        return set([obj])  # Single item
    if not isinstance(obj, set):
        obj = set(obj)
    return obj

class AllMatch(set):
    """Universal set - match everything"""
    def __contains__(self, item): 
        return True

allMatch = AllMatch()

class Event(object):
    """The Actual Event Class"""

    def __init__(self, action, minute=allMatch, hour=allMatch, 
                       day=allMatch, month=allMatch, daysofweek=allMatch, 
                       args=(), kwargs={}):
        self.mins = conv_to_set(minute)
        self.hours = conv_to_set(hour)
        self.days = conv_to_set(day)
        self.months = conv_to_set(month)
        self.daysofweek = conv_to_set(daysofweek)
        self.action = action
        self.args = args
        self.kwargs = kwargs

    def matchtime(self, t1):
        """Return True if this event should trigger at the specified datetime"""
        return ((t1.minute     in self.mins) and
                (t1.hour       in self.hours) and
                (t1.day        in self.days) and
                (t1.month      in self.months) and
                (t1.weekday()  in self.daysofweek))

    def check(self, t):
        """Check and run action if needed"""

        if self.matchtime(t):
            self.action(*self.args, **self.kwargs)

class CronTab(object):
    """The crontab implementation"""

    def __init__(self, *events):
        self.events = events

    def _check(self):
        """Check all events in separate greenlets"""

        t1 = datetime(*datetime.now().timetuple()[:5])
        for event in self.events:
            gevent.spawn(event.check, t1)

        t1 += timedelta(minutes=1)
        s1 = (t1 - datetime.now()).seconds + 1
        print "Checking again in %s seconds" % s1
        job = gevent.spawn_later(s1, self._check)

    def run(self):
        """Run the cron forever"""

        self._check()
        while True:
            gevent.sleep(60)

import os 
def test_task():
    """Just an example that sends a bell and asd to all terminals"""

    os.system('echo asd | wall')  

cron = CronTab(
  Event(test_task, 22, 1 ),
  Event(test_task, 0, range(9,18,2), daysofweek=range(0,5)),
)
cron.run()

나열된 솔루션 중 어느 것도 복잡한 cron 일정 문자열을 구문 분석하지 않습니다. 그래서 여기 croniter를 사용하는 내 버전이 있습니다. 기본 요지 :

schedule = "*/5 * * * *" # Run every five minutes

nextRunTime = getNextCronRunTime(schedule)
while True:
     roundedDownTime = roundDownTime()
     if (roundedDownTime == nextRunTime):
         ####################################
         ### Do your periodic thing here. ###
         ####################################
         nextRunTime = getNextCronRunTime(schedule)
     elif (roundedDownTime > nextRunTime):
         # We missed an execution. Error. Re initialize.
         nextRunTime = getNextCronRunTime(schedule)
     sleepTillTopOfNextMinute()

도우미 루틴 :

from croniter import croniter
from datetime import datetime, timedelta

# Round time down to the top of the previous minute
def roundDownTime(dt=None, dateDelta=timedelta(minutes=1)):
    roundTo = dateDelta.total_seconds()
    if dt == None : dt = datetime.now()
    seconds = (dt - dt.min).seconds
    rounding = (seconds+roundTo/2) // roundTo * roundTo
    return dt + timedelta(0,rounding-seconds,-dt.microsecond)

# Get next run time from now, based on schedule specified by cron string
def getNextCronRunTime(schedule):
    return croniter(schedule, datetime.now()).get_next(datetime)

# Sleep till the top of the next minute
def sleepTillTopOfNextMinute():
    t = datetime.utcnow()
    sleeptime = 60 - (t.second + t.microsecond/1000000.0)
    time.sleep(sleeptime)

스크립트를 수정했습니다.

  1. 사용하기 쉬운:

    cron = Cron()
    cron.add('* * * * *'   , minute_task) # every minute
    cron.add('33 * * * *'  , day_task)    # every hour
    cron.add('34 18 * * *' , day_task)    # every day
    cron.run()
    
  2. 1 분 후 작업을 시작하십시오.

Github의 코드


Brian이 제안한 CronTab 클래스 실행 방법에 대한 사소한 수정이 있습니다.

타이밍은 1 초가 지났으며 매 분의 끝에 1 초의 하드 루프로 이어졌습니다.

class CronTab(object):
    def __init__(self, *events):
        self.events = events

    def run(self):
        t=datetime(*datetime.now().timetuple()[:5])
        while 1:
            for e in self.events:
                e.check(t)

            t += timedelta(minutes=1)
            n = datetime.now()
            while n < t:
                s = (t - n).seconds + 1
                time.sleep(s)
                n = datetime.now()

다른 프로세스가 솔루션을 실행하기 위해 파이썬을 시작해야하기 때문에 "순수한 파이썬"방법은 없습니다. 모든 플랫폼에는 프로세스를 시작하고 진행 상황을 모니터링하는 하나 또는 20 가지 방법이 있습니다. 유닉스 플랫폼에서 cron은 오래된 표준입니다. Mac OS X에는 cron과 같은 시작 기능과 워치 독 기능이 결합되어 원하는 경우 프로세스를 살아있게 유지할 수 있습니다. 파이썬이 실행되면 sched 모듈사용하여 작업을 예약 할 수 있습니다.


Brian의 솔루션 은 꽤 잘 작동합니다. 그러나 다른 사람들이 지적했듯이 실행 코드에는 미묘한 버그가 있습니다. 또한 나는 그것이 요구에 지나치게 복잡하다는 것을 알았습니다.

누군가가 필요로하는 경우 실행 코드에 대한 더 간단하고 기능적인 대안은 다음과 같습니다.

def run(self):
    while 1:
        t = datetime.now()
        for e in self.events:
            e.check(t)

        time.sleep(60 - t.second - t.microsecond / 1000000.0)

또 다른 사소한 해결책은 다음과 같습니다.

from aqcron import At
from time import sleep
from datetime import datetime

# Event scheduling
event_1 = At( second=5 )
event_2 = At( second=[0,20,40] )

while True:
    now = datetime.now()

    # Event check
    if now in event_1: print "event_1"
    if now in event_2: print "event_2"

    sleep(1)

클래스 aqcron.At는 다음과 같습니다.

# aqcron.py

class At(object):
    def __init__(self, year=None,    month=None,
                 day=None,     weekday=None,
                 hour=None,    minute=None,
                 second=None):
        loc = locals()
        loc.pop("self")
        self.at = dict((k, v) for k, v in loc.iteritems() if v != None)

    def __contains__(self, now):
        for k in self.at.keys():
            try:
                if not getattr(now, k) in self.at[k]: return False
            except TypeError:
                if self.at[k] != getattr(now, k): return False
        return True

분산 스케줄러를 찾고 있다면 https://github.com/sherinkurian/mani를 확인할 수 있습니다. 하지만 redis가 필요하지만 원하는 것은 아닐 수도 있습니다. (저는 저자입니다) 이것은 둘 이상의 노드에서 클럭을 실행하여 내결함성을 보장하기 위해 만들어졌습니다.


나는 많은 답변이 있다는 것을 알고 있지만 다른 해결책은 데코레이터 와 함께하는 것이 될 수 있습니다 . 특정 시간에 매일 기능을 반복하는 예입니다. 이 방법을 사용하는 것에 대한 멋진 생각은 예약하려는 기능에 구문 설탕 만 추가하면된다는 것입니다 .

@repeatEveryDay(hour=6, minutes=30)
def sayHello(name):
    print(f"Hello {name}")

sayHello("Bob") # Now this function will be invoked every day at 6.30 a.m

그리고 데코레이터는 다음과 같습니다.

def repeatEveryDay(hour, minutes=0, seconds=0):
    """
    Decorator that will run the decorated function everyday at that hour, minutes and seconds.
    :param hour: 0-24
    :param minutes: 0-60 (Optional)
    :param seconds: 0-60 (Optional)
    """
    def decoratorRepeat(func):

        @functools.wraps(func)
        def wrapperRepeat(*args, **kwargs):

            def getLocalTime():
                return datetime.datetime.fromtimestamp(time.mktime(time.localtime()))

            # Get the datetime of the first function call
            td = datetime.timedelta(seconds=15)
            if wrapperRepeat.nextSent == None:
                now = getLocalTime()
                wrapperRepeat.nextSent = datetime.datetime(now.year, now.month, now.day, hour, minutes, seconds)
                if wrapperRepeat.nextSent < now:
                    wrapperRepeat.nextSent += td

            # Waiting till next day
            while getLocalTime() < wrapperRepeat.nextSent:
                time.sleep(1)

            # Call the function
            func(*args, **kwargs)

            # Get the datetime of the next function call
            wrapperRepeat.nextSent += td
            wrapperRepeat(*args, **kwargs)

        wrapperRepeat.nextSent = None
        return wrapperRepeat

    return decoratorRepeat

그런 것이 이미 있는지 모르겠습니다. 시간, 날짜 및 / 또는 달력 모듈을 사용하여 직접 작성하는 것이 쉬울 것입니다. http://docs.python.org/library/time.html을 참조 하십시오.

파이썬 솔루션에 대한 유일한 관심사는 직업의 요구가 실행 항상 될 가능성이 자동으로 재부팅이되는 뭔가 후 "부활"할 수 있다는 점이다 시스템에 의존 솔루션에 의존 할 필요가 있습니다.


PiCloud의 [1] Crons [2]를 확인할 수 있지만 작업이 자신의 컴퓨터에서 실행되지는 않습니다. 또한 한 달에 20 시간 이상의 계산 시간을 사용하는 경우 비용을 지불해야하는 서비스입니다.

[1] http://www.picloud.com

[2] http://docs.picloud.com/cron.html


서버에서 Crontab의 방법.

파이썬 파일 이름 hello.py

1 단계 : sh 파일을 만들어 이름을 s.sh로 지정하십시오.

python3 /home/ubuntu/Shaurya/Folder/hello.py> /home/ubuntu/Shaurya/Folder/log.txt 2> & 1

2 단계 : Crontab 편집기 열기

크론 탭 -e

3 단계 : 일정 시간 추가

Crontab 형식 사용

2 * * * * sudo sh /home/ubuntu/Shaurya/Folder/s.sh

이 크론은 "2 분에"실행됩니다.


pycron 패키지 가이 문제를 어떻게 해결 하는지 좋아합니다 .

import pycron
import time

while True:
    if pycron.is_now('0 2 * * 0'):   # True Every Sunday at 02:00
        print('running backup')
    time.sleep(60)

참고 URL : https://stackoverflow.com/questions/373335/how-do-i-get-a-cron-like-scheduler-in-python

반응형