Process = 운영체제에 의해 실행중인 프로그램
- 오래전에는 "컴퓨터 한대 = 하나의 프로그램"이였다. 계산기처럼 계산 프로그램 하나만 실행할 수 있었다.
- 요즘 컴퓨터는 여러 개의 게임, 크롬 등의 웹사이트를 동시에 켜 놓을 수 있다.
- 이게 가능한 것은 운영체제 덕분이다.
- 운영체제는 프로그램을 실행 시켜주고 종료 시켜준다.
Port

- 그림에 대한 설명을 하면
- 컴퓨터에는 네트워크 인터페이스가 달려 있고, 이 인터페이스에 ip가 할당된다.
- 컴퓨터마다 운영체제가 있으며 각 프로세스 1, 3을 실행중에 있다.
- 컴퓨터 A의 경우 프로세스 1이 80 포트를 점유하고 있는데 이를 '컴퓨터 A가 80번 포트를 listen'하고 있다고 한다.
- 컴퓨터 A의 프로세스 3가 외부 프로세스랑 통신하고 있는 상태이다.
- 이때 사용자는 운영체제에게 ip 111.111.111.111에서 30000번 포트를 listen한다고 요청한다.
- 111.111.111.111의 포트 30000 프로세스와 222.222.222.222의 포트 80 프로세스가 이어져 있고 이 TCP 연결을 (111.111.111.1111, 30000, 222.222.222.222, 80, TCP)로 표현할 수 있다.
- TCP란 Transmission Control Protocol으로 IP 프로토콜 위에서 연결형 서비스를 지원하는 전송계층 프로토콜로, 인터넷 환경에서 기본으로 사용한다.
- TCP의 특징으로 연결형 서비스를 제공하며, 전이중(Full Duplex) 방식의 양방향 가상 회선을 제공한다.
- 신뢰성 있는 데이터 전송을 보존한다.
- 출처 - https://dany-it.tistory.com/50
- 포트(PORT)는 운영체제가 미리 만들어두는 "가상의 전화단자"이다. 실행되고 있는 수 많은 프로세스의 혼선을 없애기 위해 하나의 프로세스가 하나의 포트만 사용할 수 있도록 운영체제가 관리된다.
- 인터넷으로 부터 특정 포트 조합으로 패킷이 들어올때, listen 중인 프로세스가 있다면 해당 프로세스로 패킷이 전달된다.
- 패킷(packet)이란 네트워크를 통해 전송하기 쉽도록 자른 데이터의 전송 단위이다.
- 만약 프로세스가 포트가 할당되어 있지 않고, 포트 번호가 사용되고 있지 않다면 운영체제는 프로세스에 해당 포트 번호를 할당한다.
- HTTP의 기본 포트는 80, HTTPS는 443이다.(이유는 없다. 약속이다.)
- 그림에서 각 컴퓨터의 1번 프로세스가 80번 포트를 사용한다. 이를 통해, 1번 프로세스가 HTTP web을 담당하는것을 유추할 수 있다.
- 또한 컴퓨터 A의 프로세스 3가 B의 프로세스 1(HTTP)에 무언가 요청하고 있다. 이를 통해 A가 클라이언트, B가 서버임을 유추할 수 있다.
gunicorn/waitress 실습
- Django의 기본적인 worker는 하나의 요청만 받아들일 수 있다.
- 새로운 Django 프로젝트를 생성
- allowed host에 0.0.0.0 추가
- urls.py 수정
from time import sleep
from django.contrib import admin
from django.http import HttpResponse
from django.urls import path
def hi(request):
print(f"processing: {request.GET.get('hi')}")
sleep(5)
return HttpResponse('hihi')
urlpatterns = [
path('admin/', admin.site.urls),
path('', hi)
]
- 요청 한 번 해보기
#mac
curl "0.0.0.0:8000?hi=1"
#window
curl http://localhost:8000?hi=1
curl -v http://localhost:8000?hi=1
? 뒤에는 전달할 데이터를 의미하고 이경우 검색어 hi의 값이 1임을 의미한다.
Pycharm Run 부분에서 processing:1이 나오는걸 확인할 수 있다.
? 뒤에 없으면 none, hi=12이면 processing:12가 나온다.
- gunicorn 설치
pip install gunicorn
- 여기서 잠깐, gunicorn은 기본 window환경에서는 돌아가지 않는다.
- 따라서 waitress라는 다른 패키지 사용을 추천한다.
pip install waitress
- 0.0.0.0은 모든 주소를 의미한다. *도 동일하다.
gunicorn guni_test.wsgi:application --bind 0.0.0.0:8000 --workers 1
waitress-serve --listen=*:8000 guni.wsgi:application
- 위의 코드를 입력하면 새로운 서버가 열린다.
- 8000번으로 켜졌음으로 원래 하고 있던 파이참 runserver는 종료해준다.

- 이후 새로운 터미널을 켜서 $ curl http://localhost:8000?hi=1를 실행하면 정상적으로 작동하고 있음을 알 수 있다.


- 하지만 실전에서는 저렇게 한번에 한 요청만 들어오지 않는다.
- 두개의 요청을 보내보자
curl "0.0.0.0:8000?hi=1" & curl "0.0.0.0:8000?hi=2" & echo "start"

- 재미있는건 분명 동기 데이터 전송인데 총 5.3초 정도의 시간 후 완료가 되었다.
- thread로 인해 비동기식으로 데이터 처리가 되었다.
- window의 문제인지는 모르겠으나..... 아래처럼 작성하면 동기식으로 데이터가 들어가진다.
- 아마도 waitress의 공식문서를 보면 threads의 default가 4라고 되어 있어서 그런거 같다.
- 참고로 threads는 process를 여러 개로 나눈 조각이다. worker를 나눈다고 생각하면 편할거 같다.
- 이를 통해 비동기 데이터 처리가 가능하다.
- 출처 - https://donghoson.tistory.com/8
$ curl http://localhost:8000?hi=1 http://localhost:8000?hi=2

$ curl http://localhost:8000?hi=1 & curl http://localhost:8000?hi=2 & curl http://localhost:8000?hi=3 & curl http://localhost:8000?hi=4 & curl http://localhost:8000?hi=5 &


- 그렇담 gunicorn처럼 worker 수를 늘릴 수 있을까?
- 대답은 아쉽게도 아니다. 출처 - https://stackoverflow.com/questions/59838433/how-does-waitress-handle-concurrent-tasks
- 하지만 thread의 수를 늘릴수는 있다.(--thread)
- 이를 통해 실험을 해보았다
$ waitress-serve --listen=*:8000 --thread=8 guni.wsgi:application

- 그림과 같이 warning이 더 이상 안뜨는 것을 확인할 수 있다. 확실하게 thread수와 관련된 경고문이였다.
- 사실 이는 waitress 코드에서 확인할 수 있는데 request를 줄때 idle_threads, queue_size등을 print 해보면 된다.
def add_task(self, task):
with self.lock:
self.queue.append(task)
self.queue_cv.notify()
queue_size = len(self.queue)
idle_threads = len(self.threads) - self.stop_count - self.active_count
if queue_size > idle_threads:
self.queue_logger.warning(
"Task queue depth is %d", queue_size - idle_threads
)
Background Process
- 프로세스는 다음과 같이 나눌 수 있다.
- foreground에서 돌아가는 프로그램(크롬, 파이참 등)
- background에서 돌아가는 프로그램(Adobe Update 등)

- 시스템에 의해 실행되어 background에서 돌아가는 프로그램을 Service 혹은 Demon이라고 한다.
- windows에서는 Serviec, linux에서는 Demon이라 불린다.
- Service
- Process와 Service는 1:1 관계가 아니다. 즉, 한 Process에서 둘 이상의 Service를 실행할 수 있다.
- 실행 파일 뿐만 아니라 dll도 Service로 구동된다.
- 서비스 < 프로세스
- Daemon
- Daemon == Background Process
- 둘 이상의 Demon이 한 Process 밑에서 작동하는 경우는 없다.
- 실행 파일만 Demon으로 구성된다.
- Demon = Process
- 출처 - https://hec-ker.tistory.com/323#:~:text='%EC%84%9C%EB%B9%84%EC%8A%A4'%EC%99%80%20'%EB%8D%B0%EB%AA%AC',%EC%95%8A%EC%95%84%EB%8F%84%20%EC%9E%90%EB%8F%99%EC%9C%BC%EB%A1%9C%20%EC%8B%A4%ED%96%89%EB%90%9C%EB%8B%A4.
Background Process에서 실행
- 명령어 뒤에 & 을 붙이면 백그라운드에서 실행한다.
sleep 15
touch hi.txt
- chmod 755 ./touch.sh를 통해 권한을 설정해준다.
- 755는 소유자는 모든 권한, 그룹 및 그 외 사용자는 읽기와 실행만 가능을 의미한다.
- 출처 - https://recipes4dev.tistory.com/175

- 위와 같이 프로세스를 하는 중에 echo가 실행되는 비동기식 처리가 보여진다.
- 백그라운에 돌려놓고 ssh 연결을 종료하면 백그라운드에서 실행되는 프로세스가 종료된다. 이를 막기 위해,
- nohup 사용
- systemctl service 사용
- 2가지 방법이 있다.
- 후자를 추천하는 바이다.
Thread
- 하나의 Process는 한 개 이상의 Threads를 가지고 있다.
- 하지만 파이썬에서는 왠만해서는 Multi Threads를 지양하고 있다. 이유는 GIL과 연결되어 있다.
- GIL = Global Interpreter Lock 으로 파이썬 인터프리터가 한 Thread가 한 Bitecode를 실행 시킬 수 있도록 해준다.
- 즉, 하나의 Thread에 모든 자원을 허락하고 그 후에 Lock을 걸어 다른 Thread를 실행할 수 없게 막는다.
- 그래서 보통은 Multi Thread가 성능이 안좋으나 sleep을 사용하여 다른 Thread로 context switching을 하여 효율이 개선된다.
- 하지만 I/O작업이 많아 Thread가 대기해야 하는 경우 Multi Thread가 성능이 더 좋다.
- 출처 - https://ssungkang.tistory.com/entry/python-GIL-Global-interpreter-Lock%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C

- 병렬 처리를하고 싶다면 하단의 두 방법을 사용하는 것이 좋다.
- Multi Process
- event loop(async io)
Debugging
- Pycharm에서 가능하다
- 오른쪽을 누르면 해당 줄이 빨간색으로 변한다. 중단점에서 코드 실행을 멈출 수 있다.
- 중단점에서 성공적으로 멈춰지면 파란색 줄로 바뀐다.


- Evaluation을 사용하면 더 많은 정보를 알 수 있다.
- 일종의 dir인데 dir의 결과까지 보여준다고 생각하면 쉽다.
- 계산기 모양을 누르면 된다.(또는 alt + f8)

- expression에 식을 적으면 실행해준다. 아래의 경우 GET만 빈칸이 아닌걸 보고 GET에 문제가 있음을 유추할 수 있다.

- 또한 type도 즉시 확인할 수 있다.
