tensor 기초

 

tensor 생성 방법
  1. torch.rand() : 0과 1 사이의 숫자를 균등하게 생성
  2. torch.rand_like() : 사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
  3. torch.randn() : 평균이 0이고 표준편차가 1인 가우시안 정규분포를 이용해 생성
  4. torch.randn_like() :  사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
  5. torch.randint() : 주어진 범위 내의 정수를 균등하게 생성, 자료형은 torch.float32
  6. torch.randint_like() : 사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
  7. torch.randperm() : 주어진 범위 내의 정수를 랜덤하게 생성
  8. torch.empty() : 임의의 행렬을 생성

 

특정 값을 가지는 tensor 생성
  1. torch.arange() : 주어진 범위 내의 정수를 순서대로 생성
  2. torch.ones() : 주어진 사이즈의 1로 이루어진 텐서 생성
  3. torch.zeros() : 주어진 사이즈의 0으로 이루어진 텐서 생성
  4. torch.ones_like() : 사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
  5. torch.zeros_like() : 사이즈를 튜플로 입력하지 않고 기존의 텐서로 정의
  6. torch.linspace() : 시작점과 끝점을 주어진 갯수만큼 균등하게 나눈 간격점을 행벡터로 출력
  7. torch.logspace() : 시작점과 끝점을 주어진 갯수만큼 로그간격으로 나눈 간격점을 행벡터로 출력

 

 

# torch 생성
x = torch.rand(3, 3)    # 3 x 3 tensor 생성
print(x)

x = torch.rand_like(x, dtype=torch.float64) # 사이즈를 기존 텐서로 정의
print(x)

x = torch.randn(3, 3)
print(x)

x = torch.rand_like(x, dtype=float)
print(x)

x = torch.zeros(3, 2)
print(x)
print(x.size())

x = torch.tensor([1, 2, 3])
print(x)
print(x.size())

 

 

tensor 연산
x = torch.rand(2, 3)
y = torch.rand(2, 3)
print(x)
print(y)

# 덧셈
print(x + y)
print(torch.add(x, y))
result = torch.empty(2, 3)
torch.add(x, y, out=result)
print(result)
print(y.add_(x))        # in-place 방식

x = torch.Tensor([[1, 3,],
                  [4, 7]])
y = torch.Tensor([[2, 4],
                  [7, 9]])
print(x)
print(y)

# 뺄셈
print(x - y)
print(torch.sub(x, y))
print(x.sub_(y))

# 곲셈
print(x * y)
print(torch.mul(x, y))
print(x.mul_(y))

# 나눗셈
print(x / y)
print(torch.div(x, y))
print(x.div_(y))

# 행렬곱 - dot
print(torch.mm(x, y))

# 인덱싱
print(x)
print(x[: 1])

 

 

tensor 기초 함수
  1. view()
  2. item()
  3. squeeze()
  4. unsqueeze()
  5. stack()
  6. cat()
  7. chuck()
  8. split()
  9. numpy()
  10. from_numpy()
  11. to()
# view - 텐서의 크기나 모양을 변경
x = torch.randn(4, 5)
y = x.view(20)
z = x.view(4, -1)   # 4 x 자동으로

print(x.shape)
print(y.shape)
print(z.shape)


# item - 텐서에 값이 단 하나라도 존재하면 숫자값을 얻을 수 있음, 스칼라 값 하나만 존재해야함
x = torch.randn(1)
print(x)
print(x.item())
print(x.dtype)


# squeeze - 차원을 축소(제거)
print('\n\n')
tensor = torch.rand(1, 3, 3)
print(tensor)
print(tensor.shape) # [1, 3, 3]

t = tensor.squeeze()
print(t)
print(t.shape)  # [3, 3]


# unsqueeze - 차원을 증가(생성)
print('\n\n')
tensor = torch.rand(1, 3, 3)
print(tensor.shape) # [1, 3, 3]

t = tensor.unsqueeze(dim=0)
print(t)
print(t.shape)  # [1, 1, 3, 3]


# stack - 텐서간 결합
print('\n\n')
x = torch.FloatTensor([1, 4])
y = torch.FloatTensor([2, 5])
z = torch.FloatTensor([3, 6])
print(torch.stack([x, y, z]))


# cat
# - 텐서를 결합하는 메소드 (concatenate)
# - 넘파이의 stack과 유사하지만, 쌓을 dim이 존재해야함.
#   . 예를 들어, 해당 차원을 늘려준 후 결합

print('\n\n')
a = torch.randn(1, 1, 3, 3)
b = torch.randn(1, 1, 3, 3)
c = torch.cat((a, b), dim=2)

print(c)
print(c.size())


# chuck - 텐서를 여러개로 나눌때 사용, 몇개의 텐서로 나눌것이냐
print('\n\n')
tensor = torch.rand(3, 6)
t1, t2, t3 = torch.chunk(tensor, 3, dim=1)
print(tensor)
print(t1)
print(t2)
print(t3)




# split - chunk와 동일한 기능이지만 조금 다름. 하나의 텐서당 크기가 얼마냐
print('\n\n')
tensor = torch.rand(3, 6)
t1, t2 = torch.split(tensor, 3, dim=1)
print(tensor)
print(t1)
print(t2)

# torch <-> numpy
#  - numpy()
#  - from_numpy()
# (참고) tensor가 cpu 상에 있다면 numpy 배열은 메모리 공간을 공유하므로 하나가 변하면, 다른 하나도 변함
print('\n\n')

a = torch.ones(7)
print(a)

b = a.numpy()
print(b, type(b))

a.add_(1)
print(a)    # a 값이 변함
print(b)    # b 값도 변함


import numpy as np

a = np.ones(7)
b = torch.from_numpy(a)
np.add(a, 1, out=a)

print(a)    # a 값이 변함
print(b)    # b 값도 변함



# CUDA Tensor
#   - .to 메소드를 사용하여 텐서를 어떠한 장치로도 옮길 수 있음
print('\n\n')
x = torch.randn(1)
print(x)
print(x.item())
print(x.dtype)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

y = torch.ones_like(x, device=device)
x = x.to(device)
z = x + y
print(device)
print(z)
print(z.to('cpu', torch.double))

ROS 1, 2, anaconda 같이 사용

  • ROS 2가 새롭게 나왔다고 하고, 앞으로는 ROS 2가 대세로 사용될거라고 한다. 
  • 그래서 공부하다 보니 ROS 1에 비해 아직은 패키지라든가 문서 등이 많지는 않은것 같다. 
  • 그래서 ROS 1을 가지고 스터디할 필요성이 느껴 ROS 1noetic, ROS 2 foxy 를 같이 설치해서 사용하기로 했다.
  • 설정을 잘 해줘야 패스 등이 꼬이지 않는다. 
  • 일단은 ros1 에서 roscore 실행되고, ros2 에서 talker 실행되는 것을 확인했다. 

 

 

ros 1, ros 2 설치

 

noetic/Installation/Ubuntu - ROS Wiki

If you rely on these packages, please support OSRF. These packages are built and hosted on infrastructure maintained and paid for by the Open Source Robotics Foundation, a 501(c)(3) non-profit organization. If OSRF were to receive one penny for each downlo

wiki.ros.org

 

 

Installation — ROS 2 Documentation: Foxy documentation

You're reading the documentation for an older, but still supported, version of ROS 2. For information on the latest version, please have a look at Humble. Installation Options for installing ROS 2 Foxy Fitzroy: Which install should you choose? Installing f

docs.ros.org

 

bashrc 설정

  • 아래 reference를 보면 보다 정확할 듯 싶다. 
  • 아래 ROS_V 를 1 or 2 로 바꾼 후, 아래 명령어를 입력해주고 사용하면된다.
    • source ~/.bashrc 
  • 아래는 내가 설정한 .bashrc 파일이다.
# conda env
alias env_base='conda activate base; echo base env activated'
alias env_ROS1='conda activate ROS1; echo ROS1 env activated'
alias env_ROS2='conda activate ROS2; echo ROS2 env activated'


# Set bashrc command
ROS_V=2 # Select ROS Version 1 or 2

if [ $ROS_V -eq 1 ]; then
    alias cw='cd ~/catkin_ws'
    alias cs='cd ~/catkin_ws/src'
    alias cm='cd ~/catkin_ws && catkin_make'

    source /opt/ros/noetic/setup.bash
    source ~/catkin_ws/devel/setup.bash
    source /usr/share/gazebo/setup.sh

    export ROS_MASTER_URI=http://localhost:11311
    export ROS_HOSTNAME=localhost

elif [ $ROS_V -eq 2 ]; then
    source /opt/ros/foxy/setup.bash
    source ~/robot_ws/install/local_setup.bash
    source ~/robot_ws/ws_moveit2/install/setup.bash

    source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash
    source /usr/share/vcstool-completion/vcs.bash
    source /usr/share/colcon_cd/function/colcon_cd.sh
    export _colcon_cd_root=~/robot_ws

    export ROS_DOMAIN_ID=7
    export ROS_NAMESPACE=robot1

    export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
    # export RMW_IMPLEMENTATION=rmw_connext_cpp
    # export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
    # export RMW_IMPLEMENTATION=rmw_gurumdds_cpp

    export RCUTILS_CONSOLE_OUTPUT_FORMAT='[{severity} {time}] [{name}]: {message} ({function_name}() at {file_name}:{line_number})'
    #  export RCUTILS_CONSOLE_OUTPUT_FORMAT='[{severity}]: {message}'
    #  export RCUTILS_COLORIZED_OUTPUT=1
    #  export RCUTILS_LOGGING_USE_STDOUT=0
    #  export RCUTILS_LOGGING_BUFFERED_STREAM=1
fi

 

 

 

 

Reference

 

ROS1, ROS2, Conda 같이 쓰기

http://wiki.ros.org/noetic/Installation/Ubuntuhttps://docs.ros.org/en/foxy/Installation.htmlhttps://www.anaconda.com/products/individua

velog.io

 

How do I prevent Conda from activating the base environment by default?

I recently installed anaconda2 on my Mac. By default Conda is configured to activate the base environment when I open a fresh terminal session. I want access to the Conda commands (i.e. I want the ...

stackoverflow.com

 

 

'ROS' 카테고리의 다른 글

[ROS] RealSense ROS 설치  (0) 2022.08.12
[ROS] Package 생성  (0) 2022.08.08

티스토리 코드 블록 폰트 크기 변경

  • 티스토리의 코드 블록을 그대로 사용할 경우, 글씨 크기가 너무 작아 가독성이 떨어진다.
  • 그래서 이번에 코드블록의 폰트 크기를 변경하는 방법에 대해 알아본다.
  • 먼저, 관리자 페이지로 들어가서
  • [꾸미기] - [스킨편집] 클릭, 그러면 아래그림과 같은 화면이 보인다.

 

  • [ html 편집 ] 클릭 후 css 클릭한 다음, "code " 로 검색
  • 아래 그림과 같이 보이는 부분에서 font 부분을 변경해주면 된다.
  • 왼쪽 블로그 화면에서 "새로고침"을 누르면 변경사항 확인 가능하다.

 

 

 

 

 

 

 

 

REFERENCE 

[ Linux ] source 명령어

  • 스크립트 파일을 수정한 후, 수정된 값을 바로 적용하기 위해 사용하는 명령어
  • 예를 들어, .bashrc 파일을 수정한다고 바로 적용되지 않음. (--> 로그아웃, 로그인)해야 적용됨
source .bashrc

 

 

[ Linux ] export, echo 명령어

  • export 명령어 : 환경 변수를 지정, 변경하거나 현재 정의되어 있는 환경 변수를 보여주는 명령어
  • echo 명령어 : 환경변수를 출력 
# echo
echo $DOMIN_ID


# export 
export TEMP_DIR=/tmp

 

 

 

[ Linux ] alias 명령어

  • 별칭으로 사용자가 명령어를 다른 이름으로 바꿔서 사용할 수 있는 쉘 내부 명령어
  • .bashrc 파일에 아래와 같이 등록해두면, 터미널에서 test 입력이 해당 디렉토리로 이동함
# alias
alias test='cd /test'

 

 

 

 

REFERENCE 

 

[ Linux 명령어 ] source 명령어란

Linux source 명령어란 source 명령어는 스크립트 파일을 수정한 후에 수정된 값을 바로 적용하기 위해 사용하는 명령어 예를 들어 /etc/bashrc 파일을 수정한 이후에 저장하여도 수정한 내용이 바로 적

chunggaeguri.tistory.com

 

[Linux, Unix] export, echo 명령어 알아보기

우리가 자주쓰는 export와 echo 명령어에 대해서 알아봅시다.

keepcalmswag.blogspot.com

 

[ 콜백 함수, lambda, map, filter 함수 ]

  • 콜백함수
  • lambda
  • map
  • filter

 

 

 

 

 

콜백 함수

  • 호출 방향이 반대임.
  • 즉, 사용자 정의 코드에서 함수를 호출하는 것이 아니라 함수에서 사용자 정의 코드를 호출하는 함수
  • 함수를 함수의 인자로 전달받아서 함수에서 인자로 전달받은 함수를 호출하는 것

 

 

lambda 함수

  • 간단한 알고리즘 코드 블록
  • 메모리에 저장 안되므로 간단한 연산에 사용
  • lambda 입력인자목록 : 수행코드(연산식)

 

 

map 함수

  • 순서가 있는 데이터들에 (ex, 리스트) 함수의 결과를 적용시키기 위해 사용

 

 

filter 함수

  • return 값이 True or False (<-- map 함수와의 차이)

 

# callback
def square(val):
    return val ** 2

def caller(func, val):
    if type(val) != str:
        return func(val)
    else:
        return 'val Error'
    
    
print(caller(square, 2))
print(caller(square, '2'))


# lambda 
res = lambda a, b : a+b


# map()
ls = list(range(10))

def even(i):
    if i % 2 == 0:
        return 'even'
    else:
        return 'odd'

print(list(map(even, ls)))

# map 없이 사용
result = []
for i in ls:
    if i % 2 == 0:
        result.append('even')
    else:
        result.append('odd')
print(result)


# filter() - return 값이 True or False (map 함수와의 차이)
ls = list(range(10))

def even(i):
    if i % 2 == 0:
        return True
    else:
        return False

print(list(filter(even, ls)))

'Python' 카테고리의 다른 글

[ Thread ] 스레드 (3) - Lock()  (0) 2022.12.16
[ Thread ] 스레드 (2) - 멀티 스레드  (0) 2022.12.15
[ Thread ] 스레드 (1)  (0) 2022.12.14
[Socket] 소켓(Socket) 프로그래밍 (1)  (1) 2022.09.21
[Python] enumerate 함수  (0) 2022.01.26
클래스
  • 클래스 개념
  • 생성자, 소멸자
  • self
  • 네임스페이스 (namespace)
  • 클래스에서의 getter / setter 사용
  • 클래스 변수(class variable) vs 인스턴스 변수(instance variable)
  • 인스턴스 메서드 & 클래스 메서드 (class method) & 정적 (static) 메서드
  • 상속 / super

 

 

클래스
  • 빵을 만드는 틀" 개념
  • 객체(object) : 클래스를 통해 만들어진 빵의 개념
  • 객체와 인스턴스 차이
    • 같은 것이나 누구 관점에서 부르르냐의 창
    • object = Test()  
      • object 는 객체라고 부르며, Test 는 클래스라고 부름
      • Test 클래스 관점에서 부르면 object는 Test의 인스턴스라고 함
    • 인스턴스 : 클래스를 실체화한것. 즉, 클래스로 객체화 한것을 인스턴스라고함
  • 메소드 : 클래스 내 함수
  • 클래스 생성 시, 대문자로 작성
# class 생성

class Person:
	pass
    
p = Person()	# 객체 생성
  • 객체를 생성하면 아래 그림과 같이 클래스와 객체가 각자 고유의 메모리 공간을 가짐

  • p.data = 3 입력 시, 아래와 같이 p 객체 공간에 {"data":3} 을 딕셔너리 형태로 저장함. 

 

생성자 (constructor), 소멸자
  • 생성자 : 클랙스 객체 생성 시 자동으로 실행되는 것. 초기값 설정 시 사용
  • 소멸자 : 클래스 인스턴스가 소멸될 때 자동으로 호출되는 함수. 일반적으로 잘 사용하지 않음
  • self   :  클래스 인스턴스, 아래의 경우, self 는 test 가 됨
# 생성자, 소멸자

class Test:
	def __init__(self, name, age):	# 생성자
    	self.name = name
        self.age = age
    
    def __del__(self):
    	print('소멸자')
    

# 객체 생성
test = Test('JS', 23)

# 객체 접근
print(test.name)
print(test.age)

 

 

self
  • 클래스 내의 인스터스를 의미함
class Foo:
    def func1():
        print(f'func1')

    def func2(self):
        print(id(self))
        print(f'func2')
        

f1 = Foo()
# f1.func1()  # error
f1.func2()

print(id(f1))   # f1 instance 주소와 self의 주소가 같음

 

 

네임스페이스
  • 변수가 객체를 바인딩할 때 그 둘 사이의 관계를 저장하는  공간을 의미함
  • 파이썬 클래스는 새로운 타입(객체)을 정의하기 위해 사용되며, 모듈과 마찬가지로 하나의 네임스페이스를 가짐

 

클래스에서의 getter / setter 사용
  • 클래스의 데이터를 직접 변경하는 것은 좋지 않음. 즉, 간접적으로 조작하는 것이 좋음 (get, set 사용)
  • 파이썬에는 private, public 개념이 없음
  • 아래 코드에서 그냥 get, set 함수를 사용하면 여전히 사용이 가능함
  • @property , @age.setter 데코레이터를 사용하여 코드를 작성하는 것이 좋음
  • 앞 언더바 2개 사용 
    • 외부에서 클래스 속성값에 접근하지 못하도록 할때
    • 오바라이딩 방지용
class Test:
	def __init__(self, name, age):
    	self.__name = name
        self.__age = age
 	
    def get(self):
        return self.__name, self.__age
    
    def set(self, name, age):
        self.__name = name
        self.__age = age
        
    @property
    def age(self):
        return self.__age


    @age.setter
    def age(self, age):
        self.__age = age
    
    
    
# 객체 생성
test = Test('JS', 11)

# 직접 변경
test.name = 'SJ'
test.age = '22'
 
# get
name, age = test.get()
print(name, age)

# set
test.set('JS', 33)
name, age = test.get()
print(name, age)


# property
print(test.age)	# getter
test.age = 20	# setter

test.name = 'DH'	#  변경 안됨

 

 

클래스 변수(class variable) vs 인스턴스 변수(instance variable)
  • 클래스 변수
    • 여러 인스턴스 간에 서로 공유해야하는 값은 클래스 변수를 사용
  • 인스턴스 변수
    • self 가 붙어있는 변수
class Account:
    num_account = 0		# class variable
    def __init__(self, name):
    	self.name = name	# intance variable
        Account.num_account += 1
        

kim = Account('kim')
lee = Account('lee')

 

인스턴스 메서드 & 클래스 메서드 (class method) & 정적 (static) 메서드
  • 인스턴스 메서드
    • 클래스에 아무 데코레이터 없이 선언된 메서드
    • 첫번째 매개 변수로 클래스의 인스턴스가 넘어옴 (= self)
  • 클래스 메서드
    • @classmethod 데코레이터를 사용하여 선언
    • 첫번째 매개 변수로 클래스 인스턴스가 아닌 클래스 자체가 넘어옴 (= cls)
    • cls 를 사용해 클래스 속성에 접근하거나 클래스 메서드를 호출 할 수 있음
    • 인스턴스 메서드와 달리 다른 인스턴스 속성에 접근하거나 다른 인스턴스 메서드를 호출하는 것은 불가능함.
    • 팩토리 메서드를 작성할 때 유용함
  • 정적 메서드
    • @staticmethod 데코레이터 사용하여 선언
    • 첫번째 매개 변수가 할당 되지 않음
    • 클래스의 일부로 선언할 필요 없지만 비슷한 메서드를 하나의 클래스에 두고 싶을때 사용
    • 정적 메서드 내에서는 인스턴스, 클래스 속성에 접근하거나 호출하는 것이 불가능
class Test:
    object_count = 0    # class variable
    
    def __init__(self, age):
        self.age = age
        
        Test.object_count += 1

    # instance method
    def add(self, age):
        return self.age + age
    
    # class method
    @classmethod
    def count(cls):
        return cls.object_count

    # static method
    @staticmethod   
    def static(name):
        print(name)


# instance method
test = Test(10)
print(test.age)

# class method
t1 = Test(10)
print(t1.count())
t2 = Test(20)
print(t2.count())

# static method
t2.static('static')

 

 

상속 / super
  • 부모 클래스(parent class, super class), 자식 클래스(child class, sub class) 
  • 메소드 오버라이딩 (method overriding)
    • 부모 클래스의 메소드를 자식 클래스에서 재정의 하는것
  • 파이썬은 다중상속이 가능함(c++가능, C#, Java 불가능)
# parent class
class Parent:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def showParent(self):
        print(self.name, self.age)

# child class
class Child(Parent):    # 상속
    def __init__(self, name, age):
        super().__init__(name, age)     # parent class init() 상속
        
    
    def showChild(self):
        super().showParent()    # method oeverriding
        print('child show')


p = Parent('JS', 10)
p.showParent()

c = Child('TT', 20)
c.showParent()  # 부모 클래스 함수도 사용 가능
c.showChild()

 

 

추상 클래스 (abstract class)
  • 추상 클래스는 메서드의 이름만 존재하는(메서드 구현 없이) 클래스
  • 부모 클래스에 메서드만을 정의하고, 이를 상속 바은 클래스가 해당 메서드를 구현하도록 강제하기 위해서 사용함
# parent class
class Car:
	@abstracmethod
    def drive(self):
    	pass
        
        
class K5(Car):
	def drive(self):
    	print('k5 drive')


car_k5 = K5()

 

'Python Tutorial' 카테고리의 다른 글

[ Python Tutorial ] 딕셔너리  (0) 2022.12.12
[ Python Tutorial ] 튜플  (1) 2022.12.10
[ Python Tutorial ] 리스트  (0) 2022.12.09
[ Python Tutorial ] 문자열  (0) 2022.12.08
[ Python Tutorial ] Print 출력  (0) 2022.12.07

스레드 (3)

  • Lock
  • global 

 

 

Lock 

  • Lock은 python threading패키지에서 지원
  • Lock을 acquire하면 해당 쓰레드만 공유 데이터에 접근할 수 있고, lock을 release 해야만
    다른 쓰레드에서 공유 데이터에 접근할 수 있음
  • 아래 코드에서 2개의 스레드로 글로벌 변수로 사용해 연산을 하면, 1억이 아닌 다른 값이 나옴
    • 같은 변수를 동시에 접근하기 때문에 발생 --> 이를 위해서 Lock 함수가 사용됨
# thread lock()
import time
import threading


shared_num = 0

def thread_func1(num):
    global shared_num
    for i in range(num):
        shared_num += 1

def thread_func2(num):
    global shared_num
    for i in range(num):
        shared_num += 1

if __name__ == "__main__":
    
    increased_num = 0
    
    start = time.time()
    
    # for i in range(100000000):
    #     increased_num += 1
    
    threads = []
    t1 = threading.Thread(target=thread_func1, args=(50000000, ))
    t1.start()
    threads.append(t1)

    t2 = threading.Thread(target=thread_func2, args=(50000000, ))
    t2.start()
    threads.append(t2)
    
    
    for t in threads:
        t.join()
    
    print(f'shared number : {shared_num}')

    end = time.time() - start
    print(end)
  • 아래 그림과 같이 Lock 해주면 연산결과가 제대로 나옴
shared_num = 0
lock = threading.Lock()     # lock()

def thread_func1(num):
    global shared_num
    
    lock.acquire()          # 다른 쓰레드가 공유 데이터 접근 금지
    for i in range(num):
        shared_num += 1
    lock.release()          # lock 해제

def thread_func2(num):
    global shared_num
    
    lock.acquire()          # 다른 쓰레드가 공유 데이터 접근 금지
    for i in range(num):
        shared_num += 1
    lock.release()          # lock 해제

 

Global

  • 위 코드에서 전역변수에 대해 함수 내에서 사용하기 위해서는 global 변수명으로 선언하면 사용할 수 있음.

 

Reference 

 

[Python] Thread and Lock (쓰레드와 락)

쓰레드(Thread)는 프로그램의 실행 흐름입니다. 하나의 프로세스 안에서 여러 개의 쓰레드를 만들 수 있습니다. 프로세스란 말은 메모리에 할당되어 있는 한 개의 프로그램을 의미하고, 프로그램

velog.io

 

 

스레드 (2) - 멀티 스레드

  • GIL (Global Interpreter Lock)
  • 멀티 프로세싱 (multi-processing)
  • 스레드 vs 프로세스

 

 

GIL (Global Interpreter Lock)

  • 파이썬에서는 하나의 프로세스 안에 모든 자원의 락(Lock)을 글로벌하게 관리함으로써 하나의 쓰레드만 자원을 컨트롤하여 동작하도록 함
  • 아래 그림에서 스레드 하나 실행 시간은 약 0.1초, 두 개 실행 실행시키면 0.2초가 나옴
    • GIL 때문, 즉 한번에 하나의 스레드만 실행 시킴
    • 두 개의 thread를 사용해서 0.1가 나오기 위해서는 멀티 프로세싱을 사용해야함.
import threading
import time 


def thread_func(num):
    for i in range(num):
        pass

def thread_func1(num):
    for i in range(num):
        pass


# # multi thread
# start_time = time.time()

# t = threading.Thread(target=thread_func, args=(10000000, ))        
# t2 = threading.Thread(target=thread_func1, args=(10000000, ))        

# t.start()
# t2.start()

# t.join()
# t2.join()

# end_time = time.time() - start_time
# print(f'elapsed time : {end_time}')

 

멀티 프로세싱 (multi-processing)

  • threading 모듈과 구현방식이 유사
  •  단점
    • 프로세스는 각자의 고유한 메모리 영역을 가지고 있기 때문에 스레드에 비해 메모리 사용량이 늘어남
  • 아래 코드의 경우, 프로세스 1개 실행 시, 0.16초, 2개 실행 시, 0.17초 정도로 동시에 실행되는 것을 확인할 수 있음
import threading
import multiprocessing as mp
import time 


def thread_func(num):
    for i in range(num):
        pass

def thread_func1(num):
    for i in range(num):
        pass

  

if __name__ == '__main__':
    start_time = time.time()

    # multi processing
    m1 = mp.Process(target=thread_func, args=(10000000, ))
    m2 = mp.Process(target=thread_func1, args=(10000000, ))
    
    m1.start()
    m2.start()
    
    m1.join()
    m2.join()


    end_time = time.time() - start_time
    print(f'elapsed time : {end_time}')

 

 

스레드 vs 프로세스

  • 파이썬에서 병렬처리를 구현하는 방식은 멀티스레드 or 멀티프로세스 방식이 있음
  • 스레드의 경우, 
    • GIL로 계산 처리 작업은 하나의 스레드에서만 작동하여 CPU 작업이 적고, I/O 작업이 많은 병렬처리에 효과적
  • 프로세스의 경우,
    • 각자가 고유한 메모리 영역을 가지므로 메모리 사용이 많음
    • 각각의 프로세스에서 병렬로 cpu 작업을 할 수 있어 여러 머신에서 동작하는 분산 처리 프로그램 구현이 가능함

 

Reference

 

Nathan's Blog

The blog to learn more.

monkey3199.github.io

 

 

 

 

'Python' 카테고리의 다른 글

[ Python ] 콜백함수, lambda, map, filter 함수  (0) 2023.01.02
[ Thread ] 스레드 (3) - Lock()  (0) 2022.12.16
[ Thread ] 스레드 (1)  (0) 2022.12.14
[Socket] 소켓(Socket) 프로그래밍 (1)  (1) 2022.09.21
[Python] enumerate 함수  (0) 2022.01.26

+ Recent posts