본문 바로가기
프로그래밍/CS

[운영체제] 멀티 프로세스/멀티 쓰레드 시간분석 비교 프로그래밍

by 엽기토기 2020. 12. 23.
반응형

PBL 시나리오 요약 및 문제 접근

신입사원의 프로세스 방식의 코딩

-> 스레드 방식으로 개발하시오!

-> 요즘은 쓰레드도 빠르게 느껴지지 않음

-> 새로운 방식의 프로그래밍?

Mission: 프로세스와 스레드의 성능비교

- 어떻게 프로그래밍 할 것인가?

- 어떤 것이 성능이 좋은가? 절대적으로 성능 차이가 나는가?

비교방법

*사인 그래프 출력 함수

-공유메모리 자원(g_count)을 각 프로세스/스레드에서 10씩 증가시켜서 라디안 값에 따른 그래프 출력

-while문 조건 : g_count <= 3,600,000

-시간복잡도 : O(n^2) (이중 반복문)

평균 (sec)

멀티

프로세스

멀티

스레드

Real

time

3.803

3.619

User

time

0.00

0.342

System

time

0.00

1.193

대체로 멀티 프로세스보다 멀티 스레드가 성능이 더 좋음

-프로세스간 문맥교환(Context Switching)시 공유 메모리 만큼 시간이 소모됨

-스레드는 Stack 외 모든 메모리를 공유하기에 전역변수 접근 용이

-프로세스는 ipc(프로세스간 통신) 필요 (shared memory- mmap 사용)

 

그러나, 멀티 스레드가 항상 성능이 좋은 것만은 아님

-스레드 생성 종료 시간이 포함됨

-처리기 성능, 프로그래밍 방식에 따라 바뀔 수 있음.

Utime과 stime이 0인 이유

Real time과 utime+stime이 같지 않은 이유

가능성 2가지

1. CPU를 점유하고 있지만 문맥교환이 너무 빨리 일어나서 프로세스가 sleeping으로 간주되어 CPU time에 측정되지 않음

2. 컴파일 하는 과정에서 최적화(optimizations)로 반복문이 제거되어서 최종 대입 연산시간만 측정됨


(소스코드)

-리눅스, C

멀티 프로세스

-소스코드

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <sys/times.h>
#include <limits.h>
#include <sys/wait.h> 
#include <sys/mman.h> 

#define CLK_TCK sysconf(_SC_CLK_TCK)
#define PI 3.141592

int(*g_count) = 0;  // 공유메모리 자원
void function()
{
	double temp; //sine값을 받을 변수

	while (*g_count <= 3600000) {
		temp = sin((*g_count)*(PI / 180)); //sin에 라디안값 넣어줌
		printf("sin(%3d)", *g_count);
		for (int j = -10; j < temp * 10; j++) { //sin값 만큼 띄워줌
			printf(" ");
		}
		printf("*\n"); //그래프 찍고 줄바꿈
		*g_count += 10;
	}
}
int main(void) {
	time_t t;
	struct tms mytms;
	clock_t t1, t2;
	if ((t1 = times(&mytms)) == -1) {
		perror("times 1");
		exit(1);
	}

	g_count = mmap(NULL, sizeof *g_count, PROT_READ | PROT_WRITE,
		MAP_SHARED | MAP_ANONYMOUS, -1, 0); // 공유메모리 사용하기위해

	pid_t pid;
	switch (pid = fork()) {
	case -1: /* fork failed */
		perror("fork");
		exit(1);
		break;
	case 0: /* child process */
		function();
		exit(0);
		break;
	default: /* parent process */
		wait(NULL);
		function();
		munmap(g_count, sizeof *g_count);
		break;
	}
	if ((t2 = times(&mytms)) == -1) {
		perror("times 2");
		exit(1);
	}
	//sleep(3);
	printf("Real time : %.2f sec\n", (double)(t2 - t1) / CLK_TCK);
	printf("User time : %.2f sec\n", (double)mytms.tms_utime / CLK_TCK);
	printf("System time : %.2f sec\n", (double)mytms.tms_stime / CLK_TCK);

	return 0;
}

 

-실행결과

멀티스레드

-소스코드

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <sys/times.h>
#include <limits.h>
#define CLK_TCK sysconf(_SC_CLK_TCK)
#define PI 3.141592

int g_count = 0;  // 쓰레드 공유자원
pthread_mutex_t mutex_lock;// 뮤텍스 객체 선언

void *t_function(void *data)
{
	//char* thread_name = (char*)data;

	pthread_mutex_lock(&mutex_lock);

	double temp; //sine값을 받을 변수

	while (g_count <= 3600000) {
		temp = sin((g_count*(PI / 180))); //sin에 라디안값 넣어줌
		printf("sin(%3d)", g_count);
		for (int j = -10; j < temp * 10; j++) { //sin값 만큼 띄워줌
			printf(" ");
		}
		printf("*\n"); //그래프 찍고 줄바꿈
		g_count += 10;
	}

	pthread_mutex_unlock(&mutex_lock);
}

int main()
{
	time_t t;
	struct tms mytms;
	clock_t t1, t2;
	if ((t1 = times(&mytms)) == -1) {
		perror("times 1");
		exit(1);
	}

	pthread_t p_thread1, p_thread2;
	int status;

	// 뮤텍스 객체 초기화, 기본 특성으로 초기화 했음
	pthread_mutex_init(&mutex_lock, NULL);

	pthread_create(&p_thread1, NULL, t_function, (void *)"Thread1");
	pthread_create(&p_thread2, NULL, t_function, (void *)"Thread2");

	pthread_join(p_thread1, (void *)&status);
	pthread_join(p_thread2, (void *)&status);

	if ((t2 = times(&mytms)) == -1) {
		perror("times 2");
		exit(1);
	}
	//sleep(3);
	printf("Real time : %.2f sec\n", (double)(t2 - t1) / CLK_TCK);
	printf("User time : %.2f sec\n", (double)mytms.tms_utime / CLK_TCK);
	printf("System time : %.2f sec\n", (double)mytms.tms_stime / CLK_TCK);

	return 0;
}

-실행결과

 

멀티 프로세스 (fork)

멀티 스레드 (pthread)



출처: https://dvlv.tistory.com/104 [dev love]

 

시간 0인 이유 추가) 프로세스에서 system call이 적음. 있어봤자 fork() mmap()

 

반응형