파이썬 멀티스레딩(Multi Threading)
from threading import *
x = Thread(target=yhb, args=('A',))
x.start()
- target : 쓰레드가 실행할 함수를 지정.
- args : target으로 지정한 함수에 넘길 인자.
- start() 함수를 실행하면 해당 쓰레드가 시작된다.
- 주의할 점) args의 자료형이 튜플이기 때문에 인자가 하나일 경우 뒤에 콤마(,)를 반드시 붙여 줘야 한다.
- 튜플 자료형 개념) https://wikidocs.net/15
Time-wait 상태 빠져나오기
OSError: [Errno 98] Address already in use
와 같은 에러가 뜬 경우, (주소 할당 에러, Binding Error)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
소켓에 위와 같은 설정을 하면 해결할 수 있다.
프로그램이 종료된 후에도 커널이 소켓의 포트를 계속 점유하고 있는 경우 프로그램을 다시 실행했을 경우(해당 포트를 다시 사용하려는 경우) 주소 할당 에러가 발생한다. 프로그램을 종료하여 소켓을 소멸시켜도 일정 기간 동안 해당 커널은 죽지 않고 유지된다. 클라이언트와 마무리되지 않은 통신을 마저 처리할 수 있도록 대기시키는 시간을 주는 것이다. 좀 더 정확하게는 연결 종료 시 마지막 패킷의 전송 실패를 방지하기 위한 상태이다. 이를 Time-wait 상태라고 한다. Time-wait 상태의 소켓이 늘어나면 서버의 소켓이 고갈되어 커넥션 타임아웃이 발생한다.
소켓에 SO_REUSEADDR 옵션 값을 TRUE(1)로 바꾸면 Time_wait 상태에 있는 소켓의 ip주소와 포트번호에 새로운 소켓에 할당할 수 있도록 설정해준다.
인코딩, 디코딩
- 인코딩 : 사람이 인지할 수 있는 형태의 데이터(문자, 이미지 등)를 약속된 규칙에 따라 컴퓨터가 받아들일 수 있는 신호로 변환하는 것.
- 디코딩 : 인코딩의 반대 개념으로, 신호(코드)를 데이터 형태로 변환하는 것.
한글 인코딩, 디코딩.
한글의 인코딩은 크게 두 가지로 나뉜다.
- 완성형 : 한글을 한 글자 단위로 하나의 독립된 문자로 인식하고 각 글자에 코드를 부여하는 방식.
- 조합형 : 초성, 중성, 종성을 독립된 문자로 보고 자음, 모음의 조합으로 글자를 표현하는 방식.
- UTF-8 : 대표적인 조합형 유니코드 인코딩 방식으로, 리눅스 계열의 os는 대부분 유니코드를 지원하기 때문에 확장성이 좋다.
조합형의 단점.
- 조합형의 경우, 초,중,종성을 분리하기 위해 2바이트를 비트 단위로 쪼개서 해석하는데 이는 구현, 처리상의 부담이 컸으며 다른 문자들과 호환할 수 없다는 단점이 있다.
- 이러한 조합형의 단점 때문에 완성형이 우리나라의 표준 인코딩 방식으로 채택되었다.
완성형의 종류.
- EUC-KR : 초기 완성형으로, 사용 가능한 코드 영역이 제한적이어서 사용빈도가 높은 2350자밖에 사용할 수 없었고 따라서 모든 한글을 표현할 수는 없었다.
- 코드 페이지 949(CP949) : Windows에서 기존의 완성형 인코딩 방식인 EUC-KR을 확장한 방식.
- 온전히 윈도우 전용의 인코딩 방식이지만 윈도우 os의 압도적인 점유율로 인해 사실상 cp949가 표준이라고 할 수 있다.
- 윈도우에서 만든 한글이 들어간 파일을 유니코드로 변환할 때 인코딩 방식을 EUC-KR로 지정하면 EUC-KR에 포함되지 않은
문자들은 제대로 변환되지 않기(깨지기) 때문에 CP949로 지정해야 한다.
모든 os, 파일 시스템의 컴퓨터에서 접속하는 웹에서는 유니코드 인코딩 방식은 UTF-8 사용을 지향한다.
한글 인코딩, 디코딩 관련 에러
*UnicodeDecodeError:'utf-8' codec can't decode byte 0xbc in position 0
- 해결 방법 : 인코딩 인자를 'utf-8'이 아닌 'cp949'로 변경해주면 된다.
Multi
1. 멀티 프로세스
: 말 그대로 프로세스를 여러 개 이용하는 것.
- 하나의 프로세스에 하나의 클라이언트를 책임진다.
- Context switching으로 인한 시스템 저하 발생한다.
※ Context switching : CPU가 하나의 Task(Process, Thread)를 실행하고 있는 상태에서 인터럽트 요청에 의해 다른 Task로 전환될 때 기존의 Task 상태 및 레지스터 값들에 대한 정보(Context)를 저장하고 새로운 Task의 Context로 교체하는 작업.
- 따라서 프로세스를 늘리는 것은 상대적으로 비효율적이다.
2. 멀티 쓰레드
쓰레드 : 프로세스 안에서 논리적으로 동작하는 하나의 작업단위.
- 같은 프로세스에 공존하는 쓰레드는 서로 힙, 코드, 데이터 영역을 공유하므로 서로 통신할 때 전역 변수나 힙 영역을 사용한다.
- 전역 변수를 사용할 때는 데이터의 일관성을 위해 mutex를 활용해 동기화시켜준다.
※ mutex : 동시간에 하나의 쓰레드만이 임계 영역에 접근할 수 있도록 막아 데이터의 일관성을 유지해주는 것 - 멀티쓰레드 또한 Context Switching으로 인한 성능 저하가 발생한다. 쓰레드의 수가 늘어날수록 임계 영역(Critical Section)에 접근하기 위한 대기 시간이 늘어난다.
- 이러한 문제를 해결하기 위해 블로킹 개념 등장, 멀티 플렉싱이 생겨났다.
3. 멀티 플렉싱
- 멀티 쓰레드에서 read, write 시의 문제점을 해결하기 위해 등장.
- 클라이언트에게 데이터가 오지 않을 경우 블로킹 상태를 유지하여 효율성을 높인다.
- 하나의 쓰레드가 여러 개의 클라이언트를 관리할 수 있다.
- 코드 구현이 복잡하다.
GIL(Global Interpreter Lock)
- 파이썬에서 쓰레드를 여러 개 생성한다고 해서 여러 개의 쓰레드가 동시에 실행되지 않는다. 정확히 특정 시점에는 단 하나의 쓰레드만 실행된다.
- 즉, 하나의 쓰레드에 모든 자원에 접근하는 것을 허락하고 그 후에는 Lock을 걸어 다른 쓰레드는 실행할 수 없게 막아버리는 것이다.
- 파이썬의 메모리 관리 체계가 기본적으로 Thread-unsafe하기 때문에 Thread Safety한 환경을 만들기 위해 Mutex를 통해 한 시점에 단 하나의 쓰레드만 실행되도록 만든 것이다.
- Context Switching 비용이 적게 들고 구현하기 효율적이지만 한 번에 한 쓰레드만이 코드를 실행시킬 수 있기 때문에 멀티 쓰레드 환경에서는 성능 저하를 불러오는 문제가 있다.
현재 시각 출력하기.
import datetime
now = datetime.datetime.now()
nowTime = now.strftime('%H:%m') # 07:35 가 출력됨.
- strfime 메소드는 시간 튜플을 받아 로컬 시간의 문자열 표현을 반환하므로 출력 형태를 원하는대로 설정할 수 있다.
- ex) now.strftime('시각 : [%H:%m]') # 시각 : [10:30] 으로 출력됨.
파이썬 전역변수 특징.
파이썬의 객체들은 mutable / immutable 두 가지로 분류할 수 있다.
immutable : 변경불가능한.
- call by value로 동작하여 값만 변경되더라도 새로운 객체로 생성 된다.
- 즉, 전역변수로 선언한 변수가 특정 함수 내에서 호출되어 사용되면 그 함수 내에서 지역변수로 새로 생성된다.
- 함수 내에서 전역변수의 값을 변경하기 위해서는 global 을 사용해야 한다.
- immutable 자료형 종류 : bool, int , str, tuple
mutable : 변경가능한.
- call by reference로 동작한다.
- 함수에 매개변수로 객체를 전달하면(parameter passing) global을 사용할 필요없이 객체의 일부를 indexing, slicing 등을 통해 변경할 수 있다.
- 하지만, 값을 재할당하려면 global을 사용해야 한다.
- mutable 자료형 종류 : list, dict, set
Mutex
쓰레드 간 공통적으로 사용하는 자원이 있을 경우 데이터의 일관성, 무결성 보장이 필요하다.
일관성, 무결성의 개념적 차이.
- 일관성(Consistency) : 사용자가 조회, 변경하는 데이터는 해당 작업이 끝날 때까지 다른 사용자에 의해 변경되지 못하게 한다.
- 무결성(Integrity) : 데이터베이스의 데이터와 구조는 변경된 순서대로 전체 데이터에 적용된다.
파이썬 Thread Lock.
- 리스트, 딕셔너리 등의 자료구조는 값을 설정할 때 원자적으로 실행되어 기본적으로 무결성을 보장한다.
- int, double 등의 자료형은 무결성이 보장되지 않는다.
- 한 번에 하나의 쓰레드만 자원에 접근가능하다.
- Lock() 활용! 데이터 수정 전에 Lock을 걸어 다른 쓰레드에서 값을 수정하지 못하게 막고, 수정 후에 Lock을 푸는 구조
Lock 메소드.
threading 모듈에 정의되어 있음.
파이썬에서,
acquire() 함수
Lock이 해제된 상태이면 Lock을 걸고,
Lock이 걸린 상태이면 다른 쓰레드에서 release() 함수 호출을 통해 Lock이 풀릴 때까지 대기한다.
release() 함수
Lock을 해제한다.
잠금 해제된 lock에서 호출되면 Runtime 에러 발생.
즉, Critical Section 진입 전에 acquire(), 빠져 나온 뒤 release()해주면 된다.
'Project' 카테고리의 다른 글
[Spring] TipMI 프로젝트 정리 (1) | 2023.02.27 |
---|---|
[파이썬] 채팅 프로그램 (2) | 2022.01.01 |
[파이썬] 소켓 기반 채팅 프로그램 제작하면서 겪었던 에러 (0) | 2021.09.28 |