검색결과 리스트
글
1-1. What is Concurrency?
<C++ cuncurrency in Action Practical Multi-threading>
Chapter 1. Hello! World of Concurrency in C++ !
@translater: nolleh
(# 역자주, 의역)
이번 챕터에서는
* 동시성과 멀티스레딩의 의미
* 왜 동시성과 멀티스레딩을 필요로 할까
* C++ 동시성 지원의 역사
* C++ 프로그램의 간단한 멀티스레딩
C++ 표준이 공개된 1998년으로부터 13년이 지난 지금, C++ 표준 커미티(# 작성자들)는 언어를 지원하고 그것의 지원라이브러리를 주요한 점검대상(overhaul)으로 제공하고 있습니다.
새로운 C++ 표준 ( C++ 11 or C++0x ) 은 2011년에 공개되었고 이것의 모든 변화의 묶음(swathe)은 C++ 의 사용을 좀더 쉽고 생산적으로 만들어 주었습니다.
C++ 11 표준에서 가장 중요한 특징은 multi_threded 프로그램에 대한 지원입니다.
처음으로 C++ 표준이 multi_threded 어플리케이션의 존재를 인정하고 라이브러리의 컴포턴트로 multi_threded 어플리케이션을 쓰기 위한 방법을 제공한 것입니다.
이 지원은 플랫폼에 의존적인 확장기능에 의지하지 않고 multi-thread 프로그램을 작성하는데 도움을 주며 따라서 호환적인 multi_threded 코드를 믿을 수 있는 동작을 보장하며 작성하게 해줍니다.
또한 프로그래머가 어플리케이션의 성능을 향상시키기 위해 일반적인 동시성을,
특히 multi-threaded 프로그래밍에 더욱 더 유의할때 등장하게 됩니다.
(# 성능향상을 위해 multi-threaded 프로그래밍을 이용할때 사용하게 됩니다.)
이 책에서는 C++로 다중스레드를 이용한 동시성 프로그램을 다루며 그것들을 가능케 하는 C++언어 특징과 라이브러리 기능들을 다룹니다. 동시성과 멀티스레딩이 무엇을 의미하는지부터 시작하여 당신의 어플리케이션에서 왜 동시성을 추구해야 하는지에 대한 내용부터 다룹니다.
왜 당신이 동시성을 사용하지 않기를 원할 것인가에 대한 내용을 살펴보고 C++ 의 동시성지원에 대한 overview를 제공하고 C++ 동시성의 간단한 예제로 이번 챕터를 마무리하겠습니다. 이미 멀티스레딩 개발 경험이 있는 독자는 이 섹션을 넘어가도 좋습니다. 다음 챕터들에서는 더 확장된 예제, 라이브러리기능들을 더 깊이 있게 다룹니다. 이 책은 멀티스레딩과 동시성을 위한 C++표준 라이브러리에 대한 레퍼런스(찾아보기)들과 함께 마무리가 됩니다.
그럼, 동시성과 멀티스레딩이란 어떤걸 의미하는 걸까요 ?
1.1 What is concurrency?
가장 간단하고 기초적인 수준에서 동시성은 두개 이상의 분리된 활동들이 동시에 일어나는 것에 대한 것입니다. 우리는 삶의 일부로 동시성을 마주하고 있죠;우리는 이야기하며 걸을 수 있고, 각각의 손으로 다른 일을 할 수 있으며, 다른사람과 함께,독립적으로 각각 살고 있습니다-내가 수영하는 동안에 당신은 football 게임을 관전할 수 있죠. 그외 등등.
1.1.1 concurrency in computer systems
컴퓨터의 용어로 동시성이란, 평행하게 하나의 시스템에서 동작하고 있는 다중의 독립된 활동입니다. (순차적으로 하나 수행후 다른 하나를 수행하는게 아니라!) 이건 새로운 현상이 아닙니다.: OS 의 multitasking 은 하나의 컴퓨터에서 다수의 어플리케이션이 동시에 task switching을 통해 동작할 수 있게 하는데, 수년간 흔히 자리잡아온 기능이며 진정한 의미의 동시성을 제공하는 다중 프로세서 high-end 서버머신의 공급은 심지어 더 오래된 이야기입니다. 새로운 것은 복수의 태스크를 그렇게 하는 척이 아닌 정말로 동시에 동작하게 하는 컴퓨터의 보급입니다.
역사적으로, 대부분의 컴퓨터는 하나의 처리기만을 갖고 있었으며 오늘날의 컴퓨터들도 많은 수가 그렇습니다.
이런 머신들은 정말로 하나의 테스크만을 한 순간에 수행할 수 있는 대신, 테스크를 1초에 여러번 스위칭 할 수 있습니다.
한 조각에서는 하나의 테스크를 하고, 그리고 다른 조각에서는 다른 테스크를 처리하고.이 반복은 테스크가 동시에 수행되는 것처럼 보입니다. 이 기법은 task switching 이라 불립니다.
우리는 이런 시스템에서도 동시성이 있다라고 여전히 얘기할 수 있습니다; 테스크 스위치가 정말 빨라서, 처리기가 다른 것으로 스위치를 할 때 어떤 지점에서 하나의 테스크가 일시 정지한다.라고 말할 수 없기 때문입니다.
테스크 스위칭은 사용자에게도, 어플리케이션 자체에 대해서도 동시성에 대한 착각을 불러일으킵니다. 동시성에대한 환상만이 있기 때문에 단독 처리기의 테스크 스위칭 환경에서 실행하는 어플리케이션의 동작은 진짜 동시성이 제공되는 환경에서의 동작과 갑자기 다를 수 있습니다.
특히, 메모리 모델에 대한(chapter 5) 잘못된 추측은 이런 환경에서 문제로 대두되지 않을 수 있습니다. 이것은 chapter 10에서 더 깊이 다뤄봅니다.
다수의 처리기를 보유한 컴퓨터는 서버에서 사용되어왔고 고성등의 컴퓨팅 테스크를 처리하기 위해 수년간 사용되어 왔습니다. 그리고 현재 하나의 칩에 하나이상의 코어가 있는 처리기(multicore processors)를 사용하는 컴퓨터는 점차 흔한 데스크탑으로 자리잡고 있습니다.
다수의 처리기를 보유하든, 다수의 코어를 하나의 프로세서에 보유하든 (혹은 둘다이든), 이 컴퓨터들은 정말로 병렬적으로 task를 처리하기위한 능력을 갖고 있습니다. 우리는 이것을 hardware concurrency라고 일컫습니다.
Figure 1.1 은 두 테스크를 10개의 동일한 사이즈로 조각 내어 동작시키는 컴퓨터의 이상적인 시나리오를 보여주고 있습니다. 듀얼 코어 머신에서는 각각의 테스크가 하나씩 코어를 사용하여 실행될 수 있습니다. 테스크 스위칭을 사용하는 하나의 코어 머신은 각각의 테스크의 조각을 끼워 넣게 됩니다.
하지만 테스크 조각만이 아니라, 아무것도 하지 않는 공간 역시 추가 되게 됩니다. (다이어그램에서 각 조각사이에서 구분 선이 듀얼 코어의 그것보다 더 두껍게 보여지고 있다.); 이 interleaving(끼워넣기)을 위해서, 하나의 테스크에서 다른 테스크로 전환할 때마다 시스템은 문맥교환을 필요로 하고,
이것에 시간이 들기 때문입니다.
문맥 교환을 수행하기 위해서 OS는 CPU 상대의 저장/현재 동작중이던 테스크의 포인터 제공/어떤 테스크로 스위치 될지 확인한 뒤 해당 테스크의 CPU 상태를 reload 합니다.
그 후, 잠재적으로 메모리에 명령(instructions)과 데이터들을 새로운 테스크를 위해 로드하고 CPU 가 명령을 수행하는 데 있어서 지연되는 일이 없도록 캐쉬에 담아야 할 것입니다. (# 메모리에 정보들을 올린뒤 캐쉬에도 올립니다.)
하드웨어의 동시성이 가능한 프로세서들에서라도 어떤 처리기들은 하나의 코어에서 복수개의 스레드를 실행할 수 있습니다. 이 결정을 위한 중요 고려 요소는 hardware threads의 '수' 입니다 : 얼마나 많은 독립된 테스크를 하드웨어가 정말로 동시성을 보장하며 수행할 수 있는가가 기준인겁니다.
하드웨어 동시성을 보장하는 시스템이라도 병렬적으로 수행 할 수 있는 수 이상으로 테스크가 많을 수 있으며 이때에는 테스크 스위칭을 이용하게 됩니다.
예를들면, 전형적인 데스크탑 컴퓨터는 평소에는 많은 작업이 없지만 백그라운드 동작을 수행하면서 수백개의 테스크를 동작시킬수 있습니다. 백그라운드 테스크를 동작시키게하는 것이 바로 테스크스위치이며 당신이 워드 프로세서, 컴파일러, 에디터, 웹브라우져를 ( 등등 ) 한번에 이용하게 합니다.
Figure 1.2 는 4개의 테스크가 듀얼코어 머신에서 이상적인 시나리오로 같은 사이즈 조각으로 나누어 테스크스위칭을 하는 것을 보여주고 있습니다. 실제상황에서는 많은 이슈들이 분할이 동등하게 이뤄지지 않도록 하며 스케쥴링 또한 정규적으로 이뤄지지 않게 합니다. 이런 이슈들의 일부는 Chapter 8에서 동시성 코드의 성능에 영향을 주는 요소를 다룰때 함께 다루고 있습니다.
이 책에서 다뤄지는 모든 테크닉, 함수, 클래스들은 당신의 어플리케이션이 싱글코어 프로세서에서 동작하든, 많은 멀티코어 프로세서에서 동작하든 동시성이 테스크 스위칭을 통해 이뤄지든, 하드웨어 동시성을 통해 이뤄지든 영향받지 않고 이용될 수 있습니다.
하지만 당신이 상상할수 있듯 당신의 어플리케이션에서 어떻게 동시성을 이용하게 구현할지는 하드웨어 동시성의 여부에 따라 의존될 수도 있습니다. 이런 내용은 chapter 8에서 다루며 C++의 코드에서 동시성을 디자인하는 내용과 함께 다루고 있습니다.
1.1.2 Approches to concurrency
프로그래머 한 쌍이 소프트웨어 프로젝트에 함께 일하는 상황을 상상해 봅시다. 만약 당신의 개발자가 다른 사무실에 있다면 둘은 각각의 작업을 서로 방해 받지 않으며 각각 자신의 작업을 레퍼런스 메뉴얼을 작성하며 분리해서 진행할 것입니다. 하지만 커뮤니케이션은 쉽지 않겠죠; 의자를 돌려서 서로 이야기하는 것이 아니라 핸드폰과 이메일로, 사무실로 걸어가서 소통해야 할 테니까요. 또한, 두 사무실이라는 오버헤드, 중복된 레퍼런스 메뉴얼의 카피라는 문제도 있습니다.
이제 당신의 짝이 같은 사무실로 이사를 왔다고 상상해봅시다. 이제 서로 자유롭게 어플리케이션의 디자인에 대해서 토론하며 쉽게 종이와 화이트보드에 디자인 아이디어와 설명을 위해 다이어그램을 그릴수도있습니다. 이제 당신은 하나의 사무실만 관리하면되며 하나의 집합의 리소스들만 있으면 대부분 충분합니다. 부정적인 측면으로는, 당신은 아마도 집중하기 힘들수도 있고 리소스를 공유하는게 문제가 될 수도 있겠습니다. ( 레퍼런스 메뉴얼 어디간거야 ? )
당신의 짝 개발자를 조직하는 이 두가지 방법이 동시성에 대한 두가지 기본적인 접근을 설명합니다. 각각의 개발자는 스레드를 의미하며, 각각의 사무실은 프로세스를 의미합니다. 첫번째 접근은 복수의 싱글스레드 프로세스를 나타내며 이건 각각의 개발자가 하나의 사무실을 보유하는 것과 비슷합니다. 그리고 두번째 접근은 다중스레드 싱글프로세스를 나타내며 이건 두 개발자를 같은 사무실에 두는것과 비슷합니다.
당신은 이 임의의 방식을 결합할수있고 멀티스레디드나 싱글스레디드인 복수 프로세스를 가질수도 있습니다. 하지만 원리는 같습니다. 이제 간략하게 동시성에 대한 두 접근을 어플리케이션에서 보도록 합시다.
Concurrency With Multiple Processes
하나의 어플리케이션에서 동시성을 만드는 첫번째 방법은 어플리케이션을 다수의 분리된 싱글스레디드 프로세스들로 나누는 것이며 이 프로세스들은 동시에 동작하여 당신이 웹브라우져와 워드 프로세서를 동시에 사용하는 것과 같습니다.
이 분리된 프로세스들은 메시지를 서로 normal interprocess communication channels ( signals, sockets, files, pipes, and so on ) 을 이용하여 Figure 1.3 처럼 교환할 수 있습니다.
이런 프로세스간의 통신의 하나의 단점은 운영체제가 다른 프로세스의 데이터를 실수로 수정하는 일이 없도록 프로세스간의 보안시스템이 구축되어있기 때문에 종종 구축에 복잡할 수 있고 느릴수도 있다는 것입니다. 다른 단점은, 다중 프로세스 구동에서의 상속된 오버헤드 입니다.: 프로세스를 실행하기 위해서는 운영체제가 관리에 필요한 리소스를 할당하는 등의 시간이 소요됩니다.
물론, 단점만 있는 것은 아닙니다: 운영체제의 추가된 보안은 일반적으로 프로세스와 고수준의 커뮤니케이션 메커니즘사이에 더 쉽게 안전한 동시성 코드를 제공합니다. (스레드 보다)
정말로, Erlang 프로그래밍 언어에서 제공되는 환경은 좋은 효과를 내기 위해 프로세스를 동시성의 근본 구축 블록으로 사용합니다.
Concurrency with multiple threads
다른 동시성에 대한 접근은 다중 스레드를 하나의 프로세스에서 구동시키는 겁니다. 스레드들은 가벼운 프로세스들과 비슷한 개념입니다: 각각의 스레드는 다른 스레드와 독립적으로 구동되며 다른 명령들의 시퀀스로 동작합니다.
하지만 모든 스레드들은 프로세스에서 같은 주소공간을 공유하며 대부분의 데이터는 모든 스레드에서 직접적으로 접근될수 있습니다- 전역 변수는 전역적으로 남아있으며 객체에대한 포인터나 레퍼런드, 데이터는 스레드 사이에서 전달될 수 있게 됩니다.
종종 프로세스들 사이에서 메모리를 공유하는 것은 가능하지만 같은 데이터에 대한 메모리 주소가 다른 프로세스에서는 필요치 않기 때문에 이건 종종 복잡하고 관리하기 어려울 수도 있습니다. Figure 1.4 에서는 하나의 프로세스에 존재하는 두 스레드가 공유된 메모리를 통하여 통신하는 모습을 보여주고 있습니다.
공유된 주소공간과 데이터 보호의 부재는 멀티플 스레드를 사용하는 데 필요한 오버헤드를 다중 프로세스를 사용하는 데 필요한 오버헤드와 비교했을때 운영체제가 기록할(bookkeeping) 필요가 더 적기 때문에 상당히 작습니다.
하지만 공유된 메모리의 유연성은 비용으로 다가 올 수도 있습니다. 만약 데이터가 다중 스레드에서 접근이 될때, 어플리케이션 프로그래머가 보여지는 데이터의 뷰를 각각의 스레드가 접근할 때마다 일관성을 유지해야하기 때문입니다. 이 스레드간 데이터 공유를 둘러싼 이슈와 피하기 위한 가이드라인들은 이 책의 3,4,5,8 chapter 에서 다루고 있습니다.
이 문제는 코드를 작성할때의 적절한 관심으로 극복할 수 있으며, 여기서 말한 적절한 관심이, 그렇다고해서 엄청난 비용을 스레드 간에 통신을 위해 필요로 한다는 것을 의미하는 것은 아닙니다.
론칭과 통신에 관계된 상대적으로 멀티프로세스에 비해 적은 오버헤드는 잠재적인 공유 메모리 문제에도 불구하고 C++ 언어를 포함하여 선호되는 접근방법이라는 것을 의미합니다.
더하여, C++ 표준은 프로세스간의 통신을 위한 어떤 내장된 지원도 하고 있지 않으므로 다중 프로세스를 이용하는 어플리케이션은 결국 플랫폼에 특화된 API 들에 의존해야 합니다.
이 책은 멀티스레딩만을 배제적으로 다룰 것이며 앞으로의 동시성에 대한 레퍼런스들 또한 다중 스레드를 통해 성취될 수 있다고 가정합니다.
동시성에 대한 의미를 갖고 이제 왜 당신의 어플리케이션에서 동시성을 사용해야 하는지 살펴봅시다.
설정
트랙백
댓글
글
Daytime.3 - An asynchronous TCP daytime server
다음에 기반함
http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/tutorial/tutdaytime3.html
main 함수
int main() { try {
먼저, 클라이언트의 연결요청을 받아들일 객체가 필요하다. io_service 객체는 소켓과 같은 I/O 서비스를 제공하므로, 이를 이용하자.
boost::asio::io_service io_service; tcp_server server(io_service);
io_service 객체를 run 하여 비동기 연산을 수행하도록 하자.
io_service.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; }
tcp_server 클래스
class tcp_server { public:
생성자에서 포트 13의 요청을 listen 하도록 초기화 해주자.
tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13)) { start_accept(); } private:
start_accept() 함수에서 소켓을 생성하고 async accept 를 시작하여 새로운 연결을 받아들이자.
void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service()); acceptor_.async_accept(new_connection->socket(), boost::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error)); }
handle_accept 는 start_accept 함수가 종료되어 accept 연산이 개시될 때 호출된다. 이 함수에서 클라이언트의 요청을 처리하고, start_accept() 를 다시 호출하여 다음 연결 요청을 받을 수 있도록 하자.
void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(); } start_accept(); }
tcp_connection 클래스
shared_ptr 과 enable_shared_from_this 를 활용하여 관련한 연산이 수행되는 한 tcp_connection 객체가 소멸되지 않도록 유지하자.
class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer; static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); } tcp::socket& socket() { return socket_; }
start() 함수에서는 boost::asio::async_write() 함수를 활용하여 클라이언트로 데이터를 전송한다.
ip::tcp::socket::async_write_some() 대신 async_write 를 사용하여 전체 데이터 블록이 전송될 수 있도록 했음을 확인하자.
void start() {
비동기로 메시지를 전송하는 것이 완료될 때까지 데이터가 유효함을 보장하기 위해 클래스 멤버로 데이터를 보관 할 것이다.
message_ = make_daytime_string();
boost::bind() 를 활용하여 비동기 연산을 수행할때, 핸들러의 parameters 와 호출부의 arguments 가 일치하도록 주의한다.
placeholder 들 (boost::asio::placeholders::error / boost::asio::placeholders::bytes_transferred) 이 handle_write() 에서 사용되지 않기때문에, 실수로 제거될 수 있다.
boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
이 연결에 필요한 기타 추가 작업들은 이제 handle_write() 에서 모두 처리하면 된다.
} private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service) { } void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) { } tcp::socket socket_; std::string message_; };
불필요한 핸들러 인자 제거
우리의 예제에서, error 와 bytes_transsferred 인자는 handle_write 함수 몸체에서 불필요하다. 이러한 경우, 함수에서 이를 제거하여 다음과 같은 시그니쳐를 갖게 할 수 있다.
void handle_write() { }
이 함수를 호출부인 boost::asio::async_write() 를 호출할때에는 다음과 같이 수정하면 된다.
boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this()));
정리
1. main 함수
* tcp_server 에 io_service 를 전달하여 생성하고, tcp_server 클래스를 initiate 한다.
* 메인 스레드에서 tcp_server 에서 사용하는 io_service 의 run() 함수 호출
2. tcp_server 클래스
* boost::asio::ip::tcp::begin_accept 를 활용하여 클라이언트의 연결을 받고, tcp_connection 객체를 생성한다.
* connection 의 start 함수를 호출한다.
* 완료 된 후, 다음 연결을 받기 위해 다시 accept 를 시작한다.
3. tcp_connection 클래스
* enable_shared_from_this 를 활용하여 이 객체에 대한 연산이 수행되는 경우 소멸되지 않도록 보장한다.
* 클라이언트로 전달하는 데이터가 소멸되지 않게 하기 위해, 클래스의 멤버로 데이터를 보전한다.
* 전송 데이터가 분리되지 않게 하기 위해 async_write() 함수를 활용
* 사용하지 않는 place_holder 를 제거하여 핸들러 인자의 시그니쳐를 단순히 가져 갈 수도 있다 (async_write)
Full source code
--
#pragma once #include#include #include #include "boost/shared_ptr.hpp" #include "boost/asio.hpp" #include "boost/bind.hpp" #include "boost/enable_shared_from_this.hpp" //* enable_shared_from_this 를 활용하여 이 객체에 대한 연산이 수행되는 경우 소멸되지 않도록 보장한다. //* 클라이언트로 전달하는 데이터가 소멸되지 않게 하기 위해, 클래스의 멤버로 데이터를 보전한다. //* 전송 데이터가 분리되지 않게 하기 위해 async_write() 함수를 활용 //* 사용하지 않는 place_holder 를 제거하여 핸들러 인자의 시그니쳐를 단순히 가져 갈 수도 있다(async_write) class TCPConnection : public boost::enable_shared_from_this { public: typedef boost::shared_ptr pointer; static pointer create(boost::asio::io_service& io) { return pointer(new TCPConnection(io)); } boost::asio::ip::tcp::socket& socket() { return socket_; } void start() { message_ = make_daytime_string(); boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&TCPConnection::handle_write, shared_from_this())); } private: TCPConnection(boost::asio::io_service& io) : socket_(io) { } void handle_write() { std::cout << message_ << ", write_done" << std::endl; } std::string make_daytime_string() { std::time_t now = time(0); return ctime(&now); } boost::asio::ip::tcp::socket socket_; std::string message_; }; //* boost::asio::ip::tcp::begin_accept 를 활용하여 클라이언트의 연결을 받고, tcp_connection 객체를 생성한다. //* connection 의 start() 함수를 호출한다. //* 완료 된 후, 다음 연결을 받기 위해 다시 accept 를 시작한다. class TCPServer { public: TCPServer(boost::asio::io_service& io) : acceptor_(io, boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), 13)) { start_accept(); } private: void start_accept() { TCPConnection::pointer new_connection = TCPConnection::create(acceptor_.get_io_service()); // async_accept(socket, ACCEPT_HANDLER); acceptor_.async_accept(new_connection->socket(), boost::bind(&TCPServer::handle_accept, this, new_connection, boost::asio::placeholders::error)); } void handle_accept(TCPConnection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(); } start_accept(); } boost::asio::ip::tcp::acceptor acceptor_; }; //* tcp_server 에 io_service 를 전달하여 생성하고, tcp_server 클래스를 initiate 한다. //* 메인 스레드에서 tcp_server 에서 사용하는 io_service 의 run() 함수 호출 void server_run() { try { boost::asio::io_service io_service; TCPServer server(io_service); io_service.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } }
'Programming > Boost asio' 카테고리의 다른 글
Daytime.2 - A synchronous TCP daytime server (0) | 2015.04.19 |
---|---|
Daytime.1 - A synchronous TCP daytime client (0) | 2015.04.13 |
Tutorial 5. Synchronising handlers in multithreaded programs (0) | 2015.04.11 |
Tutorial 4. member function handler (0) | 2015.03.17 |
Tutorial 3. Binding arguments to a handler (0) | 2015.03.15 |
설정
트랙백
댓글
글
Learn You Some Erlang
몰랐는데,
learn you ~
시리즈북이 원래 있었나보다. (하스켈도 있다고 그러고. )
근래에 몇달째 functional programming 과 Rx 쪽으로 스터디가 집중되다보니,
말이 펑셔널 펑셔널 하게 짠다지, 좀 잘해보려면 공부를 많이 해야할 것 같아서 .. (현업에서 쓰고있는 부분은 없으니... )
learn You some erlang
http://learnyousomeerlang.com/
을 팀내에서 세미나 형태로 공유하고 있다. - 라고 쓰고 그냥 팀분들께 하는 사기극일지도..-
내용을 잘 정리해서 블로깅을 하거나, 아예 제대로 ? 한글로 번역 - 해서 출판하고 싶은 욕망이 샘솟긴 하는데..
(출판할 수 있을까 ? - 이 끝없는 명예욕....)
일단은 급한대로 한주 한주 세미나를 진행하는 것으로 만족.
다음 github repo 에 매주 발표자료를 업로드 하고 있다.
https://github.com/nolleh/learnyouerlang
다음은 1주차 내용.
https://github.com/nolleh/learnyouerlang/blob/master/week1/week1.pdf
뭔가....첨엔 뭐이렇게 문법이 직관적이지가 않아.. 라고 했다가..
6주째 자료를 만드는 지금은
얼랭 짱짱맨인듯...