정의: 하나의 processor가 여러 가지 task를 동시 수행하는 개념
특징: task를 전환해서 효율적으로 여러 개의 task를 동시에 수행하는 것 같음
동기: 한 작업이 끝난 후에 다른 작업 수행가능(대기 시간엔 대기함), 일이 순차적으로 진행이 되어 요청과 요청에 대한 응답이 연속적 실행.
비동기: 대기 시간에 다른 일을 처리함, 일이 비순차적으로 진행이 되어 요청과 요쳥에 대한 응답이 연속적이지 않아서 특정 코드의 연산이 끝날때 까지 코드의 실행을 멈추지 않고 다음 코드 먼저 실행하는 콜백함수로 연결
정의: 유사한 task를 여러 processor 동시에 수행
특징:
processor의 개수만큼 퍼포먼스 수행
동시성이 요구할 때 병렬성의 효율 극대화.
여러 개의 프로세스가 1개의 task를 여러 개의 subtask쪼개어 수행
Bound: 어떤 일을 바로 하지 못하고 대기해야 하는 일
I/O Bound: 입출력에서 데이터 처리 시간이 소요
CPU Bound: 복잡한 수식 계산이나 그래픽 작업과 같은 엄청난 계산 필요 시 사용
정의: 프로그램 구동하여 프로그램 자체와 상태가 메모리 상에서 실행되는 작업 단위
특징:
스케줄링의 대상이 되는 작업(task)
운영체제의 커널에서 시스템 자원(CPU,메모리,디스크)및 자료구조 이용
프로그램을 구동하여 프로그램 자체와 상태가 메모리 상에서 실행되는 작업 단위
여러 프로세스를 사용하는 것을 멀티 프로세싱이라고 한다
프로세스 관리는 os의 중요한 부분이다
자신만의 전용 메모리 공간(Heap)가진다.
커널
생성(create): 프로세스가 생성되는 중이다
실행(running): 프로세스가 cpu를 차지하여 명령어들이 실행
준비(ready): 프로세스가 CPU를 사용하진 않지만 언제든 사용 가능한 상태. 우선순위 순으로 CPU할당됨
대기(waiting): 보류라고 부른다. 입출력 완료, 시그널 수긴 등 어떤 사건을 기다리는 상태
종료(terminated): 프로세스의 실행이 종료됨
프로세스의 상태전이
- 디스패치(dispatch)
: 준비 상태에서 실행 상태로 바뀌는 것
dispatch (processname) : ready -> running
보류(block)
: 허가된 시간을 다 쓰기 전에 입출력 동작이 필요한 경우 CPU반납하여 보류 상태로 감
block (processname) : running -> blocked
깨움(wakeup)
: 보류 상태에서 준비 상태로 넘어가는 과정
wakeup (processname) : blocked -> ready
시간제한(timeout)
: 프로세스가 프로세서를 독점하지 못하게 일정시간동안만 점유하도록 함
: timeout (processname) : running ->ready
정의: 프로세스 내에서 실행되는 흐름의 단위
특징: 한 프로세스 안의 스레드들이 메모리 공간을 공유하지만 다른 프로세스랑은 안함
정의: 코드에서 시스템의 어느 부분이 느린지 혹은 어디서 RAM을 사용하는지 확인 기법
특징:
- 코드의 병목을 찾아 성능 측정
정의: 한 대의 컴퓨터 성능을 최적화 시키기
특징:
- 단일 서버(하드웨어)의 성능 증가시켜 더 많은 요청 처리
- CPU, 메모리, 하드디스크 등을 업그레이드 혹은 증가시킴
- 별도의 서버 추가하지 않기에 데이터 정합성 이슈에 자유로움
- 별도의 소프트웨어 라이선스 추가 비용 발생 않음
- 구현이 어렵지 않음
단점:
하나의 서버 장비에는 cpu, 메몰, 디스크의 수 제한이 있다.
- 한정된 자원을 초과하여 성능을 증가하기 위해선 서버 자체 변경
일정 수준이 넘어가는 순간 성능 증가 폭이 미미해짐
성능 증가 대비 업그레이드 비용이 굉장히 비쌈
서버 한 대가 모든 클라이언트의 트래픽을 감당해야 하기에 과부화가능.
정의: 여러 대의 컴퓨터를 한 대처럼 사용하는 것
특징:
- 동일 사양의 새로운 서버를 추가하여 성능 증가
단점:
- 서버가 늘어날때 마다 소프트웨어 라이선스 비용이 증가한다.(오픈소스 활용으로 비용 줄이기)
여러 대의 서버로 하나의 서비스를 사용하려면 데이터 불일치가 잠재적으로 발생
정합성 이슈에서 자유로울 수 없다.
*기본코드
class Delivery:
def run(self):
print("delivery")
class RetriveDish:
def run(self):
print("Retriving Dish")
work1 = Delivery()
work2 = RetriveDish()
def main():
work1.run()
work2.run()
if __name__ == '__main__':
main()
*멀티스레드
# threading 모듈을 import
# 클래스에 Thread를 상속
from threading import *
class Delivery(Thread):
def run(self):
print("delivery")
class RetriveDish(Thread):
def run(self):
print("Retriving Dish")
work1 = Delivery()
work2 = RetriveDish()
def main():
work1.run()
work2.run()
if __name__ == '__main__':
main()
*스레드 생성 확인
# 함수 이름을 출력하면 함수 객체 확인
from threading import *
class Delivery:
def run(self):
print("delivering")
work1 = Delivery()
print(work1.run)
class Delivery(Thread):
def run(self):
print("delivering")
work2 = Delivery()
print(work2.run)
2-1. 스레드 생성 방식
threading 모듈의 Thread 클래스 상속 받아 구현
인스턴스화 시킨다
i) Thread클래스에 인자로 target과 args값 넣기
ii) args에 넣어 준 파라미터는 스레드 함수의 인자로 넘어감
t = Thread(target=함수이름, args=())
Thread클래스에는 start(), join()같은 동작관련 메소드가 있고 실행 함수 정의 후 start() 통해 스레드 실행
# 수행코드
from threading import *
from time import sleep
Stopped = False
def worker(work, sleep_sec): # 일꾼 스레드입니다.
while not Stopped: # 그만 하라고 할때까지
print('do ', work) # 시키는 일을 하고
sleep(sleep_sec) # 잠깐 쉽니다.
print('retired..') # 언젠가 이 굴레를 벗어나면, 은퇴할 때가 오겠지요?
t = Thread(target=worker, args=('Overwork', 3)) # 일꾼 스레드를 하나 생성합니다. 열심히 일하고 3초간 쉽니다.
t.start() # 일꾼, 이제 일을 해야지? 😈
#종료 코드
# 이 코드 블럭을 실행하기 전까지는 일꾼 스레드는 종료하지 않습니다.
Stopped = True # 일꾼 일 그만하라고 세팅해 줍시다.
t.join() # 일꾼 스레드가 종료할때까지 기다립니다.
print('worker is gone.')
import multiprocessing as mp
def delivery():
print('delivering...')
p = mp.Process(target=delivery, args=())
p.start()
p = mp.Process(target=delivery, args=())
p.start() # 프로세스 시작
p.join() # 실제 종료까지 기다림 (필요시에만 사용)
p.terminate() # 프로세스 종료
정의: 스레드나 프로세스들로 가득 찬 풀장
방식:
1. Queue 사용하여 직접 만들기
concurrent.futures
: 라이브러리의 ThreadPoolExecutor, ProcessPoolExecutor클래스 이용
concurrent.futures모듈이란?
기능:
Executor 객체
*서브클래스
*메소드
ThreadPoolExecutor 객체
with ThreadPoolExecutor() as executor:
future = executor.submit(함수이름, 인자)
*Delivery클래스 이용
from concurrent.futures import ThreadPoolExecutor
class Delivery:
def run(self):
print("delivering")
w = Delivery()
with ThreadPoolExecutor() as executor:
future = executor.submit(w.run)
*multiprocessing.Pool.map을 이용하여 여러 개의 프로세스에 특정 함수 매핑하여 병렬 처리
from multiprocessing import Pool
from os import getpid
def double(i): # pool을 통해 각각 다른 pid를 가진 프로세스 위에 multiprocess실행
print("I'm processing ", getpid()) # pool 안에서 이 메소드가 실행될 때 pid를 확인해 봅시다.
return i * 2
with Pool() as pool:
result = pool.map(double, [1, 2, 3, 4, 5])
print(result)