👨🏽‍💻

ch3 - 2. 시간 스케쥴 매니저 (time, cron)

time, datetime

Index

  • 1. 개요
  • 2. time 모듈
    • 2.1. time.time()
    • 2.2. time.sleep()
  • 3. datetime 모듈
    • 3.1. datetime.datetime.now()
    • 3.2. timedelta 자료형
    • 3.3. 특정 시각까지 프로그램 멈추기
    • 3.4. datetime 객체를 String 으로 변환하기
    • 3.5. String을 datetime 객체로 변환하기

1. 개요

업무자동화의 핵심은, 우리가 해야 할 반복적이고 지루한 일을 컴퓨터가 자동으로 처리해주는 것입니다. 우리의 컴퓨터는 우리가 컴퓨터 앞에 앉아 있지 않아도, 특정 날짜와 시각에, 또는 주기적으로 어떠한 프로그램을 실행시킬 수 있습니다. 예를 들어 당신이 어떤 웹사이트를 한 시간에 한 번씩 체크해야 할 때, Python의 timedatetime 모듈을 활용하면 우리가 자고 있을 오전 4시에도 컴퓨터가 당신의 일을 대신 처리해줄 수 있습니다. 또한 Python의 subprocessthreading 모듈을 사용하여, 여러 프로그램들을 동시에 실행시킬 수도 있습니다.
 
파이썬 프로그램에서 시간을 다루기 위해서는 해당 프로그램이 구동되는 운영체제가 제공하는 시간 기능을 활용하게 되는데 파이썬에서 이 부분을 처리하는 것이 time 모듈과 datetime 모듈입니다.
time 모듈이 제공하는 함수에서는 실수형의 형태로 시간에 대한 정보를 제공하는데, 이는 인간에게 익숙한 것이 아니므로 파이썬에서는 일, 월, 시, 분, 초 등 인간에게 친숙한 형태로 시간에 대한 정보를 이용할 수 있는 datetime 모듈이 있습니다.

2. time 모듈

time 모듈은 운영체제에서 제공하는 여러 가지 시간과 관련된 모듈로서 다양한 기능을 제공하며, 이 기능들은 운영체제마다 다른 결과를 나타냅니다. time.time()과 time.sleep()은 그 중에서 자주 쓰는 기능으로 time.time()은 운영체제의 현재 시간을 구하는데 사용하고, time.sleep()은 주어진 시간 동안 프로그램을 일시적으로 멈추는데 사용합니다.

2.1. time.time()

time.time()은 현재 시간을 Unix Epoch인 1970년 1월 1일 0시 0분 0초 이후 경과한 시간을 실수형 값으로 반환합니다. 시간대는 UTC를 사용합니다. 사용자의 입장에서 친숙한 형태가 아니긴 합니다.
 
  • 용어
    • Epoch 시간 기원 - 기준 시간. 중요한 사건, 변화가 일어난 시간 기원.
    • Unix Epoch - 유닉스가 출현한 기원. 1970년 1월 1일 새벽 0시.
    • Time Stamp - 일반적으로, 어떤 기준 시간(Epoch)부터 경과한 시간을 수치 값으로 주는 문자열. 운영체제나 프로그램에 따라 다르다. 기준 시간으로부터 몇 초가 지났는지 나타내는 수로 단순히 하루를 86800초로 계산해 순차적으로 증가.
 
time.time()함수로 현재 시각 구하는 코드 입니다.
import time #time 모듈 임포트 time.time() #현재 시각
이 코드의 실행결과는 아래와 같습니다.
1552825720.5182314
이는 time.time()으로 호출한 시점이 Unix Epoch로부터 약 1,552,825,720초 경과했다는 의미입니다.
 
현재 시간을 친숙한 형태인 년, 월, 일, 시, 분, 초로 나타내려면 기준 시간(Unix에서는 Unix Epoch)에서 현재 시간까지 경과된 초를 이용해 환산해야 한다.
 

2.2. time.sleep()

time.sleep()은 프로그램을 주어진 시간 동안 일시적으로 멈추도록 합니다.
time.sleep()을 사용하는 코드
import time for i in range(5): print('Ha') time.sleep(1) print('Ho') time.sleep(1)
이 코드의 실행 결과는 아래와 같습니다.
Ha Ho Ha Ha Ho Ha
 

3. datetime 모듈

datetime 모듈은 time 모듈이 사용자의 입장에서 친숙한 형태가 아닌 실수형 값으로 운영체제의 현재 시간을 반환하는 것에 비해 일, 월, 시, 분, 초 등 날짜와 시각의 형태로 시간에 대한 정보를 이용할 수 있게 해줍니다.
 
datetime 모듈은 datetime 데이타타입을 가지고 있습니다.

3.1 datetime.datetime.now()

datetime.now()함수는 현재 시간을 반환
datetime.now()를 사용하는 코드
import datetime dt = datetime.datetime.now() # 현재 시간을 dt에 지정 dt
이 코드의 실행 결과는 아래와 같습니다.
datetime.datetime(2019, 3, 22, 0, 16, 40, 83816)
앞서 time 모듈에서 살펴본 Unix epoch timestamp 는 datetime.datetime.fromtimestamp() 함수를 통해 datetime 객체로 변환될 수 있습니다. The date and time of the datetime object의 날짜와 시각은 현지 시간대로 변환됩니다.
datetime.datetime.fromtimestamp() 를 사용하는 코드
datetime.datetime.fromtimestamp(1000000) 는 Unix epoch 로부터 1000000초가 지난 시각을 datetime 객체로 반환합니다.
import datetime datetime.datetime.fromtimestamp(1000000)
실행 결과
datetime.datetime(1970, 1, 12, 5, 46, 40)
 
datetime.datetime.fromtimestamp() 를 사용하는 코드
time.time() 은 현재 시각을 나타내며, 아래 코드는 현재 시각 timestamp를 datetime 객체로 반환합니다.
import time import datetime datetime.datetime.fromtimestamp(time.time()) # datetime.datetime.now() 도 똑같은 결과값을 반환함
실행 결과
datetime.datetime(2019, 04, 09, 11, 13, 0, 604980)

3.2. timedelta 자료형

 datetime 모듈은 timedelta 라는 자료형을 제공하는데, 이것은 어떤 순간으로서의 시각이 아닌 지속되는 시간을 나타냅니다.
timedelta 객체를 생성하기 위해, datetime.timedelta() 함수를 사용합니다. dateteime.timedelta() 함수는 weeksdayshoursminutessecondsmilliseconds, 그리고 microseconds 라는 키워드 인자를 받습니다. 여기에는 month나 year 키워드 인자가 없는데, 월이나 연도는 특정 월 또는 연도에 따라 가변적이기 때문입니다. timedelta 객체는 days, seconds, microseconds로 나타내어지는 전체 기간을 가지고 있습니다.
In
#1 delta = datetime.timedelta(days=11, hours=10, minutes=9, seconds=8) #2 delta.days, delta.seconds, delta.microseconds
Out
(11, 36548, 0)
위 예제에서, 우리는 11일, 10시간, 9분, 8초라는 기간에 대한 키워드 인자를 datetime.delta() 에 전달했으며, 반환된 timedelta 객체를 delta 안에 저장했습니다. (코드의 #1 부분) timedelta 객체인 deltadays attribute는 11을 저장하고, seconds attribute는 10시간 9분 8초를 초로 나타낸 36548을 저장합니다. (코드의 #2 부분)
 

total_seconds()

total_seconds() 함수는 지속시간(초)를 리턴합니다. timedelta 객체를 str()에 넘겨 주면 객체를 사람이 읽기 좋은 형식으로 표현할 수 있습니다.
In
print(delta.total_seconds()) print(str(delta))
Out
986948.0 '11 days, 10:09:08'
total_seconds() 함수를 호출하면 11일 10시간 9분 8초는 986,948초라는 것을 알려줍니다. 마지막으로, timedelta 객체를 str() 에 전달하면 이 기간을 '11 days, 10:09:08'와 같이 명확히 말해줍니다.
 

D-Day 계산하기

이 산술 연산자를 사용하여, datetime 값에 대한 날짜 연산을 수행할 수 있습니다. 예를 들어, 지금으로부터 1,000 일 후 날짜를 계산하는 코드를 보겠습니다.
In
dt = datetime.datetime.now() print(dt) thousandDays = datetime.timedelta(days=1000) print(dt + thousandDays)
Out
2019-04-10 02:47:52.136640 2022-01-04 02:47:52.136640
 

사칙연산으로 timedelta 객체 다루기

timedelta 객체는 또다른 datetime 객체 또는 timedelta 객체에 대하여 +, - 연산이 가능하고 timedelta 객체는 정수 또는 실수에 대하여 *, / 연산이 가능합니다.
In
oct21st = datetime.datetime(2019, 10, 21, 16, 29, 0) aboutThirtyYears = datetime.timedelta(days=365 * 30) print(oct21st) print(oct21st - aboutThirtyYears) print(oct21st - (2 * aboutThirtyYears))
Out
2019-10-21 16:29:00 # oct21st 1989-10-28 16:29:00 # oct21st - aboutThirtyYears 1959-11-05 16:29:00 # oct21st - (2 * aboutThirtyYears)

3.3. 특정 시각까지 프로그램 멈추기

 time.sleep() 메서드를 사용하면 특정 시간 (초) 동안 프로그램을 일시 중지 할 수 있습니다. while 루프를 사용하면 특정 날짜까지 프로그램을 일시 중지 할 수 있습니다. 예를 들어 다음 코드는 2020년 할로윈까지 계속 반복됩니다.
import datetime import time halloween2020 = datetime.datetime(2020, 10, 31, 0, 0, 0) while datetime.datetime.now() < halloween2020: time.sleep(1)

3.4. datetime 객체를 String 으로 변환하기

Epoch 타임 스탬프와datetime 객체는 사람이 보기에는 친숙하지 않습니다. datetime 객체를 문자열로 표시하려면strftime()메서드를 사용하세요. (strftime ()함수의 이름에서 f는 format을 나타냅니다.)
strftime ()메서드는 파이썬의 문자열 형식과 유사한 지시어를 사용합니다. [표 12-1]
 
notion imagenotion image
 
strrftime() 에 대한 인자로, formatting directives(슬래시, 콜론 등)을 포함하는 사용자 정의 형식 문자열을 전달하면 strftime()datetime 객체의 정보를 formatted string 형식으로 반환합니다.
In
oct21st = datetime.datetime(2019, 10, 21, 16, 29, 0) print(oct21st.strftime('%Y/%m/%d %H:%M:%S')) print(oct21st.strftime('%I:%M %p')) print(oct21st.strftime("%B of '%y"))
Out
2019/10/21 16:29:00 04:29 PM October of '19

3.5. String을 datetime 객체로 변환하기

'2019/10/21 16:29:00'이나 '2019. 10. 21'과 같은 날짜 정보 문자열을 datetime 객체로 변환해야하는 경우 datetime.datetime.strptime() 메서드를 사용하세요. strptime() 함수는 strftime() 메소드의 반대입니다. strptime () 이 문자열을 분리하고 인식하는 방법을 알 수 있도록 strftime ()과 동일한 directives를 사용하는 사용자 정의 형식 문자열이 파라미터로 전달되어야합니다. (strptime () 함수의 이름에 있는 p는 parse를 나타냅니다.)
In
datetime.datetime.strptime('October 21, 2019', '%B %d, %Y')
Out
datetime.datetime(2019, 10, 21, 0, 0)
In
datetime.datetime.strptime('2019/10/21 16:29:00', '%Y/%m/%d %H:%M:%S')
Out
datetime.datetime(2019, 10, 21, 16, 29)
In
datetime.datetime.strptime("November of '63", "%B of '%y")
Out
datetime.datetime(2063, 11, 1, 0, 0)
 

multithreading

Index

  • Multithreading 개요
  • Python으로 다른 프로그램 실행하기
  • 다른 Python Scripts 실행하기
 

Multithreading 개요

멀티스레드에 대해 설명하기 전에, 프로세스와 스레드의 개념부터 알아봅시다. 운영체제에서 프로세스(process)란, 현재 실행 중인 프로그램(program)입니다. 이 프로세스는 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 스레드로 구성됩니다.
스레드(thread)란 프로세스(process) 내에서 실제로 작업을 수행하는 주체를 뜻합니다. 하나의 프로세스에는 한 개 이상의 스레드가 존재하여 그 프로세스에 대한 작업을 수행합니다. 두 개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스(multi-threaded process)라고 말합니다. 멀티스레드를 활용하면 동시에 여러 개의 작업을 처리할 수 있습니다.
 
별도의 스레드를 만들려면 먼저 threading.Thread () 함수를 호출하여 Thread 객체를 만들어야합니다. 새 파일에 다음 코드를 입력하고 threadDemo.py로 저장합니다.
In
# threadDemo.py import threading, time # 1 print('Start of program.') def takeANap(): time.sleep(5) print('Wake up!') threadObj = threading.Thread(target=takeANap) # 2 threadObj.start() # 3 print('End of program.')
 
def takeANap()에서는 새로운 스레드에서 사용하고자하는 함수를 정의합니다. Thread 객체를 만들려면 threading.Thread ()를 호출하고 키워드 인수 target = takeANap 을 전달합니다. 즉, 새 스레드에서 호출 할 함수는 takeANap ()입니다. 키워드 인수는 target = takeANap()이 아니라 target = takeANap입니다. 당신은 takeANap () 함수 자체를 인수로 전달하고자 하는 것이지, takeANap ()을 호출하여 이것의 반환 값을 전달하고자 하는 것이 아니기 때문입니다.
threadObjthreading.Thread ()에 의해 생성 된 Thread 객체를 저장 한 후에는 threadObj.start () 를 호출하여 새 스레드를 만들고 새 스레드에서 대상 함수를 실행하기 시작합니다. 이 프로그램을 실행하면 출력은 다음과 같이 보입니다.
Out
Start of program. # 1 End of program. # 3 Wake up! # 2
 
왜 Wake up!부터 출력되지 않고 End of program.부터 출력될까요? print('End of program.') 이 프로그램의 마지막 줄이기 때문에, 마지막으로 출력되어야한다고 생각할 수 있습니다. Wake up!이 먼저 출력되지 않는 이유는 threadObj.start ()가 호출될 때 threadObj의 대상 함수인 takeANap()이 새로운 실행 스레드에서 실행되기 때문입니다.
메인 스레드는 새로 생성된 스레드와는 별도로 계속 프로그램을 진행하여, print('End of program.') 을 출력합니다. 한편, time.sleep (5) 호출을 실행 한 새 스레드는 5 초 동안 일시 중지됩니다. 5 초간 낮잠을 자고 나서, 'Wake up!' 을 출력하고 takeANap () 함수를 종료합니다. 시간순으로, 'Wake up!'은 프로그램에서 마지막으로 인쇄됩니다.
 
일반적으로, 단일스레드에서는 파일의 마지막 코드 행이 실행되거나 sys.exit () 함수가 호출되면 프로그램이 종료됩니다. 하지만 threadDemo.py에는 두 개의 스레드가 있습니다. 첫 번째는 프로그램 시작시 시작되고 print('End of program.') 출력 후 끝나는 메인 스레드입니다. 두 번째 스레드는 threadObj.start ()가 호출 될 때 만들어지며 takeANap () 함수가 시작될 때 시작하고 takeANap ()이 리턴 된 후에 끝납니다.
 
파이썬 프로그램은 모든 스레드가 종료 될 때까지 종료되지 않습니다. threadDemo.py를 실행할 때 원래 스레드가 종료 되었더라도 두 번째 스레드는 여전히 time.sleep (5) 호출을 실행하고 있습니다.

Python으로 다른 프로그램 실행하기

 
파이썬 프로그램은 내장 서브 프로세스 모듈의 Popen () 함수로 컴퓨터의 다른 프로그램을 시작할 수 있습니다. Popen () 함수의 이름에서 P는 프로세스를 나타냅니다.
파이썬 스크립트에서 외부 프로그램을 시작하려면 프로그램의 파일 이름을 subprocess.Popen ()에 파라미터로 전달하세요. (Windows에서는 응용 프로그램의 시작 메뉴 항목을 마우스 오른쪽 단추로 클릭하고 속성을 선택하여 응용 프로그램의 파일 이름을 확인하고 OS X에서는 응용 프로그램을 CTRL- 클릭하고 패키지 내용 표시를 선택하여 실행 파일의 경로를 찾습니다). 실행 된 프로그램은 Python 프로그램과 다른 스레드에서 실행됩니다.
 
Windows에서 대화식 쉘에 다음을 입력하세요.
import subprocess calcProc = subprocess.Popen('c:\\Windows\\System32\\calc.exe')
Ubuntu Linux에서는 다음을 입력하세요.
import subprocess subprocess.Popen('/usr/bin/gnome-calculator')
계산기 프로그램이 실행될 것입니다. 이런 식으로 엑셀, 워드, 웹 브라우저 등 다른 프로그램도 실행할 수 있습니다.
 

다른 Python Scripts 실행하기

다른 응용 프로그램과 마찬가지로 Python에서 Python 스크립트를 시작할 수 있습니다. python.exe 실행 파일을 Popen ()에 전달하고, 그 인수로 실행하려는 .py 스크립트의 파일 이름을 전달하면 됩니다. 예를 들어, 다음 코드는 hello.py 스크립트를 실행합니다.
import subprocess subprocess.Popen ([ 'C : \\ python34 \\ python.exe', 'hello.py']) # OUTPUT : <subprocess.Popen object at 0x000000000331CF28>
Popen ()에 Python 실행 파일 경로 문자열과 스크립트 파일 이름 문자열을 포함하는 목록을 전달하십시오. 실행중인 스크립트에 명령 줄 인수가 필요한 경우 스크립트의 파일 이름 뒤에 목록에 추가하십시오. Windows에서 실행 가능한 Python의 위치는 C : \ python34 \ python.exe입니다. OS X에서는 /Library/Frameworks/Python.framework/Versions/3.3/bin/python3입니다. Linux에서는 / usr / bin / python3입니다.
파이썬 프로그램을 모듈로 임포트하는 것과는 달리, 파이썬 프로그램이 다른 파이썬 프로그램을 시작하면 두 프로그램은 별도의 프로세스로 실행되며 서로의 변수를 공유할 수 없습니다.
 

cron 스케줄 관리하기

Index

  • 리눅스 작업 스케줄러
  • cron이란?
  • crontab
  • crontab 파일형식 예제
  • 주의할점

1. 리눅스 작업 스케줄러

windows에 작업 스케줄러가 있는것처럼 리눅스나 Mac OS X에는 cron이라는 작업 스케쥴러가 내장되어 있습니다. 하지만 윈도우즈는 GUI(Graphic User Interface)로 되어 있어 따로 학습이 필요없이 화면을 보고 간단하게 설정을 할 수 있지만 리눅스는 쉘에서 텍스트 형태로 작성을 해야하기 때문에 따로 학습이 필요합니다. 따라서 cron에 대해서 구체적인 예시를 들어 설명을 하도록 하겠습니다.
 

2. cron이란?

cron은 주기적으로 반복되는 일(특정한 명령이나 스크립트)을 자동적으로 실행될 수 있도록 만들어주는 프로그램입니다.
 

3. crontab

위와 같은 cron작업을 설정하는 파일을 crontab 파일이라고 합니다.
cron 작업을 하기위해서는 crontab 명령어를 이용하면 됩니다.
 
notion imagenotion image
각각의 명령에서 대해서 예시를 보여드리며 설명드리겠습니다.
 

3-2) crontab -e

# Edit this file to introduce tasks to be run by cron. # # Each task to run has to be defined through a single line # indicating with different fields when the task will be run # and what command to run for the task # # To define the time you can provide concrete values for # minute (m), hour (h), day of month (dom), month(mon), # and day of week (dow) or use '*' in these fields (for 'any'). # Notice that tasks will be started based on the cron's system # daemon's notion of time and timezones. # # Output of the crontab jobs (including errors) is sent through # email to the user the crontab file belongs to (unless redirected). # # For example, you can run a backup of all your user accounts # at 5 a.m every week with: # 0 5 * * 1 tar - zcf / var/backups/home.taz /home/ # # For more information see the manual pages of crontab(5) and cron(8) # # m h dom mon dow command
위 화면은 리눅스 쉘(shell)에서 아무 설정도 하지 않고 crontab -e를 누르면 나오는 창입니다. 위 창은 예약작업을 설정, 수정할 수 있는 창이며, 주석으로 된 코드는 명령문을 작성해야 할 때 주의할 점, 명령문 작성 방식에 대한 설명입니다. 또한 주기적으로 반복할 일에 대한 명령은 맨 아래 줄에 직접 입력하고 저장하면 됩니다. 지금부터는 이해를 돕기위해 예제를 보여주면서 하나씩 자세히 설명드리겠습니다.
 

3-3) crontab -l

# 작업 목록이 비어있는 경우 $ crontab -l no crontab for user
# 작업 목록이 있는 경우 $ crontab -l 1 5 * * * /home/user/test/start.sh
현재 작업목록을 확인할 수 있는 명령어이며 작업목록이 있을 때와 없을 때 구분이 된다는 점을 알 수 있습니다.
 

3-4) crontab -r

$ crontab -l 1 5 * * * /home/user/test/start.sh $ crontab -r $ crontab -l no crontab for user
crontab -l 을 통하여 작업목록이 있는 것을 확인하였지만 crontab -r 을 입력하면 원래 있던 작업목록이 삭제됩니다.
 
notion imagenotion image

파일 형식의 이해를 돕기 위해 다양한 예제를 보여주면서 어떤 뜻을 담고 있는 지 알려드리겠습니다.

4. crontab 파일 형식 예제

4-1) 매분 실행

//1분마다 해당하는 명령어를 실행합니다. * * * * * /home/test/start.sh
 

4-2)여러시간을 정하고 실행

//매일 오전 8시 30분, 오후 8시 30분에 해당하는 명령어를 실행합니다. 30 8,20 * * * /home/test/start.sh //매일 매시간 0분, 20분 마다 해당하는 명렁어를 실행합니다. 10,20 * * * * /home/test/start.sh
 

4-3)범위 실행

//매일 오전 9시에 해당하는 명령어를 실행합니다. (0 - 일요일, 6 - 토요일) 0 9 * * 0-6 /home/test/start.sh //월~금 오전 9시에 해당하는 명령어를 실행합니다. (1 - 월요일, 5 - 금요일) 0 9 * * 1-5 /home/test/start.sh //매일 10시 0분부터 30분까지 해당하는 명령어를 실행합니다. 0-30 10 * * * /home/test/start.sh
 

4-4)일정한 간격을 두고 실행

// 모든 날 30분마다 해당하는 명령어를 실행합니다. */30 * * * * /home/test/start.sh

 
위 예제와 같은 코드를 사용자에 맞게 crontab -e 을 통해서 입력하고 사용하시면 됩니다.
 

5. 주의할점

 

5-1) 한 줄에 하나의 명령만 써야합니다.

#잘못된 경우 0-30 10 * * * /home/test/start.sh #올바른 경우 0-30 10 * * * /home/test/start.sh
 

5-2) crontab -r 실수

그런일이 일어나면 안되겠지만 실수로 crontab -r 을 누르면 crontab 작업목록들이 모두 삭제됩니다. 그런 상황을 방지하기 위해서 주기적으로 백업을 하는 코드를 추가하면됩니다.
#매일 자정에 crontab -l 내용을 txt파일에 저장합니다. 0 24 * * * crontab -l > /home/user/backup/crontab_backup.txt