객체지향 프로그래밍
절차지향 프로그래밍으로큰 프로그램을 만들려 할 때 스파게
티 코드가 되기 쉽다.
큰 것보다는 작은 것이 관리하기 편하지 않을까?
전체 프로그램을 객체라는 것으로 나누어 객체사이의 관계로
프로그램을 만든다.
내가 축구 게임을 만든다면?
선수, 경기장, 관객, 점수 등의 부분 부분을 모두 객체로 만
든다
모든 것이 Class!
8.
클래스는 필드와 메서드로구성
필드 : 객체가 가지고 있는 변수 -> 객체의 상태
메소드 : 객체가 가지고 있는 함수 -> 객체의 행동
자바는 객체가 없이는 실행도 되지 않는다!
public void main(string args) {
System.out.println("Hello Ybigta!")
}
9.
(순수) 함수형 프로그래밍
여러분답은 함수입니다!
1. 변수가 없다 -> 불변객체(immutable object)
2. 부작용이 없는 순수함수 (pure function)
3. 함수가 1급 객체(first class citizen)
먼저 왜 FP이왜 주목받는지 알아보자
성능을 향상 시키기 위해 멀티쓰레드를 사용해보자
멀티쓰레드란?
크롤링 해야할 페이지가 100개
프로그램 하나(싱글쓰레드) 가 100개 순서대로 하지말고
10명의 일꾼(멀티쓰레드)가 10개씩 나눠서 하자
멀티쓰레드로 성능향상, 행복코딩 가즈아ㅏㅏㅏㅏ
12.
멀티쓰레드의 문제점
기본적으로 프로그래밍순서는 프로그래머가 정한다
a = 1
a = 2
print(a)
a = 1이 먼저 실행되고 a=2가 나중에 실행되었으니까 결과
는 당연히..
하지만 멀티쓰레드는 쓰레드끼리 독립적이기 때문에 순서를 예
측할 수 없다!
멀티쓰레딩 예시(Golang)
counter :=0
for i:=0; i<2; i++ {
go func(){ //멀티쓰레드로 1을 더하는 함수
counter += 1
}()
}
time.Sleep(time.Second * 3)
fmt.Println(counter)
// counter의 값은?
15.
원래라면 1씩 순서대로2번을 더해서 2이 되어야 하는데,
1을 동시에 2번 더하는 멀티쓰레딩으로 빠르게 2을 만든다.....?
결과는 2이 아닐 수도 있다.
16.
멀티쓰레드 천국편
1. counter=0을a 쓰레드가 읽는다.
2. a 쓰레드가 0에 1을 더한다.
3. a 쓰레드가 1을 counter에 쓴다.
4. b 쓰레드가 counter=1을 읽는다.
5. b 쓰레드가 1에 1을 더한다.
6. b 쓰레드가 2를 counter에 쓴다
7. counter=2
17.
멀티쓰레드 지옥편
1. counter=0을a 쓰레드가 읽는다
2. counter=0을 b 쓰레드가 읽는다
3. a 쓰레드가 0에 1을 더한다.
4. b 쓰레드가 0에 1을 더한다.
5. a 쓰레드가 1을 counter에 쓴다
6. b 쓰레드가 1을 counter에 쓴다
7. counter=1
18.
불굴의 컴퓨터 과학자들
멀티쓰레드의공유자원 문제를 해결하기 위해 다양한 방법은
제시
뮤텍스, 세마포어, 파이썬의 Global Interupt Lock (GIL) 등
자세한 내용이 궁금하시다면 운영체제를 들으세요
문제는 코딩하기가 너무 어렵다
19.
다시 한 번FP
이런 병렬적 프로그래밍을 쉽게 할 수 있는 것이 함수형 언어
순수 함수
입력 값이 같다면 출력 값이 항상 같은 함수
def like(something):
return "I like " + something
like("ybigta")
like("ybigta")
like("ybigta")
# I like ybigta
# I like ybigta
# I like ybigta
20.
비순수 함수
I/O(네트워크, 파일등)을 사용하거나 전역변수를 사용하여 입력
이 같아도 출력이 달라질 수 있는 함수
global_str = "I like "
# 전역변수 사용
def like(something):
global_str += something
return global_str
like("ybigta")
like("ybigta")
like("ybigta")
# I like ybigta
# I like ybigtaybigta
# I like ybigtaybigtaybigta
21.
FP와 병렬 프로그래밍
순수함수+ 불변객체 -> 멀티쓰레드 천국편
불변객체 : 멀티쓰레드가 언제 데이터를 읽던 상관없이 항상 똑
같다
순수함수 : 함수의 인풋이 똑같으면 결과가 항상 똑같다
순수함수에 파라미터로 불변객체를 넣는다면?
결론적으로 어떤 순서로 쓰레드가 진행되는지 항상 같
은 작업을 하기 때문에 순서를 신경쓸 필요없다!
22.
1급 객체란?
1. 변수나데이터에 할당할 수 있다
2. 객체의 인자로 넘길 수 있다
3. 객체의 리턴값으로 넘길 수 있다.
23.
함수의 1급 객체란?
파이썬의경우 함수가 1급 객체다!
1. 함수를 변수에 할당
def add_one(a):
print(a+1)
# add_one 함수가 변수 f1에 할당
f1 = add_one
f1(0)
# 1
2. 함수를 함수의 인자로 전달
a = [1, 2, 3]
b = list(map(lambda x: x+1, a))
print(b)
# [2, 3, 4]
# map 함수에 익명함수를 인자로 전달
24.
3. 함수를 리턴값으로전달
def return_add_func(value):
def add_func(x):
return x+value
return add_func
# def add_func(x): return x+1 리턴
add_one_func = return_add_func(1)
b = add_one_func(3)
# b = 4
#def add_func(x): return x+2 리턴
add_two_func = return_add_func(2)
b = add_two_func(3)
# b = 5
25.
함수형 프로그래밍은 효율적일까?
불변객체라는것은 결국 상태가 변할 때 마다 새로운 객체를 만
들어야 한다는 것이다.
아까 축구게임을 다시 생각해보자
경기장이라는 객체는 선수들의 위치를 필드로 가지고 있다.
불변객체가 아니라면 선수들의 위치가 바뀔 때 필드 값만
변경시키면 됨
불변객체라면 바뀔 수 없기 때문에 변경된 위치를 필드값
으로 갖는 경기장 객체를 다시 만들어야 한다
비효율적!
26.
그럼 함수형 프로그래밍은비효율적인가?
프로그래밍 언어에서 C가 매우 빠르다.
그러나 같은 프로그램을 python으로 짠다면?
실행속도가 느리다
But 짜는 내가 빠르다
따라서 생산성 증가
함수형 프로그래밍도 비효율적이지만 병렬 프로그래밍에서 생
산성이 좋다(내가 짜기 쉽다).
따라서 어차피 싼(?) 메모리 좀 비효율적으로 쓰고, 비싼 내 시간
과 정신건강을 효율적으로 쓰자는 합리적 선택 ㅎㅎ
특징
잡종 함수형 프로그래밍
JVM을사용하여 JAVA와 호환이 가능하다
컴파일 언어이지만, 인터프리터로도 사용가능
static언어이지만 타입추론 가능
Immutable data structure
Lazy evaluation(call by name)
이곳에서 해보자
29.
잡종 함수형 프로그래밍
순수함수형언어는 변수가 없지만
스칼라는 변수선언 가능
val a = 1 // 상수로 선언
a = 2 // 에러
var b = 1 // 변수로 선언
b = 2 //가능
30.
순수함수형 언어는 for문이 없어 recursive 함수만 가능하지만
스칼라는 for loop 가능
// recursive로 1부터 10까지 출력하기
def rec_print(start:Int, end:Int):Unit = {
if (start<=end) {
println(start)
rec_print(start+1, end)
}
}
rec_print(1, 10)
// for loop로 1부터 10까지 출력하기
for (i <- 1 to 10){
println(i)
}
// foreach 함수로 출력하기
(1 to 10).foreach(println)
31.
type 추론 가능한static 언어
자바는 compile 언어로 타입이 지정되어야 하는 static 언어
파이썬은 interpreter 언어로 타입이 동적으로 변형되는
dynamic 언어
def hello(a):
return a+1
hello("new") # a에 string이 들어가면 자동으로 string으로 변함
# new1
hello(2) # a에 int가 들어가면 자동으로 int로 변함
# 3
스칼라는 기본적으로 static 언어지만 생략하더라도 컴파일러가
type을 알아서 유추한다.
var a: Int = 1 // type을 int라고 알려줌
var a = 1 // int라고 알려주지 않았지만 값을 보고 알아서 추론
32.
Immutable data structure
함수형프로그램은 효율적인가?를 다시 살펴보자!
매번 새로운 객체를 만드는 것은 너무 비효율적..
방법이 없을까?
바로 불변객체를 위한 자료구조를 따로 만드는것!
객체를 새로 만들기는 하지만, 재사용한다
mutable data structure보다는 비효율적이지만 충분히 사용가능
하다
35.
Lazy Evaluation(Call byname)
call by _ : 함수에 parameter로 객체를 넘길 때 어
떻게 넘길 것인지에 대한 방법
C, C++은 call by value , call by reference
python은 call by object reference
scala는 call by value , call by name
36.
Call by value
함수에객체를 parameter로 넘길 때 그 값을 넘기는 방법
스칼라에서는 함수를 paramter로 넘길 수 있다는 것 기억하시
나요?
즉, 함수를 call by value로 넘기면 함수의 리턴값을 넘깁니다.
Call by name
함수에 객체를 parameter로 넘길 때 이름을 넘기는 것
말 그대로 이름입니다
즉, 함수를 call by name로 넘기면 함수의 이름을 넘깁니다.
def take_long_time_job():String ={
println("job start")
Thread.sleep(5000L) //5초 동안 쉬고
println("job done")
"Yes I'm done!" // string을 return
}
엄청 오래 걸리는 작업을 가정해 봅시다.
39.
def call_by_value(check:Int, x:String):Unit = {
if (check==1) { // check가 1이면
println(x) // x를 출력
} else { // check가 1이 아니면
println("I will not do") //x가 아닌 다른걸 출력
}
}
Call by value는 x: String 처럼 변수:타입 으로 표현합니다.
40.
def call_by_name(check:Int, x:=> String):Unit = {
if (check==1) { // check가 1이면
println(x) // x를 출력
} else { // check가 1이 아니면
println("I will not do") //x가 아닌 다른걸 출력
}
}
Call by name은 x: => String 처럼 변수: => 타입 으로 표시
합니다.
41.
이제 String을 return하는 함수 take_long_time_job 을 각각
파라메터로 넘겨봅시다.
println("Call by value")
call_by_value(1, take_long_time_job())
println("")
println("Call by name")
call_by_name(1, take_long_time_job())
// Call by value
// job start
// job done
// Yes I'm done!
//
// Call by name
// job start
// job done
// Yes I'm done!
42.
Check가 1이기 때문에두 방법 다
take_long_time_job 을 실행하고 string을 리턴받아
출력하고 있습니다.
하지만 check != 1이면 어떨까요?
43.
println("Call by value")
call_by_value(0,take_long_time_job())
println("")
println("Call by name")
call_by_name(0, take_long_time_job())
// Call by value
// job start
// job done
// I will not do
//
// Call by name
// I will not do
44.
- Call byvalue는 parameter로 넘어갈 때 이미 실행
돼서 리턴값인 string이 전달되기 때문에, 실제 x가
출력이 되든 안되든 take_long_time_job 을 실행합
니다
- Call by name은 parameter로 넘어갈 때 이름만 넘
어가기 때문에, 실제 x가 사용되지 않는다면,
take_long_time_job 을 실행하지 않습니다.
- 따라서 lazy evaluation이 가능합니다.
기본 변수 종류
AnyVal
Any
AnyRef(java.lang.Object)
Double Float Long Int Short Byte Unit Boolean Char List Option YourClass
Null
Nothing
첫 글자가 대문자 인것 주의!
48.
if 문
파이썬
a =1
if a==1:
print(a)
else:
print("Not 1")
스칼라
val a = 1
if (a==1) {
println(a)
} else {
println("Not 1")
}
val b = if (a > 0) a else 0 // 짧게도 가능
49.
for 루프
파이썬
for iin range(5):
print(i)
# 0 1 2 3 4
a = list(1, 2, 3, 4, 5)
for x in a:
print(x)
# 1 2 3 4 5
50.
스칼라
for (i <-0 to 4) {
println(i)
}
// 0 1 2 3 4
val a = List(1, 2, 3, 4, 5)
for (x <- a) {
println(x)
}
// 1 2 3 4 5
a.foreach{println}
// 1 2 3 4 5
0 to 4 는 0부터 4까지 임을 주의!
foreach 는 map 함수와 같이 모든 변수에 함수를 적용하지만,
이때 이 함수는 return 이 없어야 한다.
51.
함수선언
파이썬
def func1(x, y):
returnx+y
스칼라
// function 선언은 다음과 같이
val sum = (x: Int, y:Int) => x+y
// method 선언은 다음과 같이
def sum(x: Int, y: Int): Int = {
x+y // 마지막 줄을 자동으로 return 합니다.
}
// 이렇게 짧게 쓸수도 있습니다.
def sum(x: Int, y: Int): Int = x+y
// return 하는 값이 없을 때는 Unit이라고 표시합니다.
def print_hello(): Unit = {
println("hello")
}
52.
클래스
파이썬
class Member(object):
def __init__(self,name, team):
self.name = name
self.team = team
def hello(self):
print(f"Hello {self.name} from {self.team}")
mem = Member("Taeoh", "Engineering")
mem.hello()
# Hello Taeoh from Engineering
53.
스칼라
class Member(name: String,team: String) { // private member
// public member로 사용하려면
// class Member(var name: String, var team: String)
def hello(): Unit =
println(s"Hello $name from $team")
}
val mem = new Member("Taeoh", "Engineering")
mem.hello()
// Hello Taeoh from Engineering
이 외에도 클래스의
constructor
override method
private member의 getter, setter 등이 존재합니다.
54.
자료구조
List
값을 변경할 수없는 링크드 리스트
val a = List(1, 2, 3)
println(a(0)) // python과 다르게 a[0]이 아닌 a(0)임에 주의
val b = List.range(4, 6) // List(4, 5)
val c = a::b // a와 b를 연결 List(1, 2, 3, 4, 5)
val d = 1::2::3::Nil //링크드 리스트 이므로 List(1, 2, 3)
함수형 프로그래밍에 잘 어울리는 자료구조로
case matching 에 자주 활용됩니다.
55.
Array
값의 변경 가능한배열
val a = Array(1, 2)
println(a(0))
a(0) = 2
Array는 reference 타입의 자료구조로, val a 와 같이 불변 객체
로 선언되더라도 객체의 주소가 바뀌지 않으면 배열의 값은 변
견 가능하다.
56.
tuple
tuple 역시 immutable하면 접근 방식이 독특하다
val c = (1, 2)
println(c._1)
// 1
println(c._2)
// 2
위와 같이 {tuple value}._{index} 형태로 접근하며
주의할점은 0이 아닌 1 부터 시작한다
57.
메인 메소드
만약 스칼라를컴파일해서 사용하려면, 스칼라는 JVM 위에서 작동
하는 언어이기 때문에 메인 메소드가 필요합니다.
object Main {
def main(args: Array[String]): Unit =
println("Hello, ybigta")
}
58.
이 외의 Scala
tailrecursive
high order function
List case match
등 수 많은 것들을 다루지 않았으니 관심있으신 분들은 참고자료를
살펴보세요
Essential Scala
하마님 블로그
또한 이 곳에서 직접 프로그래밍 하며 해볼 수도 있습니다.
30분 스칼라 - 프로그래머스
30 Days of Code - Hackerrank
1. 병렬 처리프레임워크
멀티 쓰레딩 수준이 아닌 멀티 노트를 활용한 병렬처리
2. RDD (Resilient Distributed Datasets)
Immutable한 record
3. Lazy Evaluation
transformation 연산은 실제 실행하지 않고 있다가 action 연산
에서 실행
4. Coarse-grained function
모든 자료에 동일한 함수를 적용시킴
5. Ad-hock query
실시간으로 쿼리를 날릴 수 있다.
62.
Scala와 같이 살펴보기
1.함수형 언어
스칼라는 병렬프로그래밍에 생산성이 높은 함수형 언어이며, 순
수 함수형 언어가 아닌 객체지형 패러다임 역시 받아들여 실용
적이다.
2. Imutable Objcet
스칼라는 불변객체를 언어적으로 강제하지는 않지만, 불변 객체
를 사용하길 추천한다.
63.
3. Call byname(Lazy evaluation)
스칼라는 Call by name으로 함수를 인자로 넘길 때, 실제 그 함
수가 불릴 때 까지 실행되지 않는 lazy evaluation을 지원한다.
4. map, filter, foreach등 함수 콤비네이터 제공
리스트에 같은 함수를 적용시킨다.
5. 인터프리터 지원
자바와 다르게 컴파일 언어임에도 인터프리터 기능을 지원한다.
따라서 한 줄 한 줄 바로 실행할 수 있다.
그 전에 spark를notebook처럼 사용하는
방법!
jupyter noteook 대신 아파치 제플린(Apache Zeppelin) 사용한
다. 시각화가 좋아요!
jupyter notebook에 scala spark를 사용하기 위해 아파치 토리를
설치한다.
그냥 모든 것이 다 깔려있는 주피터 도커 이미지를 사용한다.
Databricks 무료 클라우드를 이용한다