programing tip

C ++ 20에서 코 루틴은 무엇입니까?

itbloger 2020. 10. 5. 07:43
반응형

C ++ 20에서 코 루틴은 무엇입니까?


에서 코 루틴은 무엇입니까 ?

"Parallelism2"또는 / 및 "Concurrency2"(아래 이미지 참조)와 어떤 점에서 다른가요?

아래 이미지는 ISOCPP에서 가져온 것입니다.

https://isocpp.org/files/img/wg21-timeline-2017-03.png

여기에 이미지 설명 입력


추상적 인 수준에서 코 루틴은 실행 스레드를 갖는 아이디어에서 실행 상태를 갖는 아이디어를 분리합니다.

SIMD (단일 명령어 다중 데이터)에는 여러 "실행 스레드"가 있지만 실행 상태는 하나뿐입니다 (여러 데이터에서만 작동 함). 아마도 병렬 알고리즘은 하나의 "프로그램"이 다른 데이터에서 실행된다는 점에서 이와 비슷합니다.

스레딩에는 여러 "실행 스레드"와 여러 실행 상태가 있습니다. 둘 이상의 프로그램과 둘 이상의 실행 스레드가 있습니다.

코 루틴은 여러 실행 상태를 갖지만 실행 스레드를 소유하지 않습니다. 프로그램이 있고 프로그램에 상태가 있지만 실행 스레드가 없습니다.


코 루틴의 가장 쉬운 예는 다른 언어의 생성자 또는 열거 형입니다.

의사 코드에서 :

function Generator() {
  for (i = 0 to 100)
    produce i
}

Generator라고하며 그것을 처음 호출이 반환됩니다 0. 상태가 기억되고 (코 루틴의 구현에 따라 상태가 얼마나 달라지는 지) 다음에 호출 할 때 중단 된 지점에서 계속됩니다. 따라서 다음에 1을 반환합니다. 그런 다음 2.

마지막으로 루프의 끝에 도달하고 함수의 끝에서 떨어집니다. 코 루틴이 완성되었습니다. (여기서 일어나는 일은 우리가 말하는 언어에 따라 다릅니다. 파이썬에서는 예외가 발생합니다).

코 루틴은이 기능을 C ++로 가져옵니다.

코 루틴에는 두 종류가 있습니다. 스택 및 스택리스.

스택리스 코 루틴은 상태와 실행 위치에 로컬 변수 만 저장합니다.

스택 형 코 루틴은 스레드와 같은 전체 스택을 저장합니다.

스택리스 코 루틴은 매우 가볍습니다. 내가 읽은 마지막 제안은 기본적으로 함수를 람다와 같은 것으로 다시 작성하는 것과 관련이 있습니다. 모든 지역 변수는 객체의 상태가되며 레이블은 코 루틴이 중간 결과를 "생성"하는 위치로 /에서 점프하는 데 사용됩니다.

코 루틴은 협동 멀티 스레딩과 비슷하기 때문에 값을 생성하는 과정을 "수익"이라고합니다. 실행 지점을 호출자에게 다시 양보합니다.

Boost에는 스택 형 코 루틴이 구현되어 있습니다. 당신을 위해 항복하는 함수를 호출 할 수 있습니다. 스택 형 코 루틴은 더 강력하지만 더 비쌉니다.


코 루틴에는 단순한 생성기보다 더 많은 것이 있습니다. 유용한 방식으로 코 루틴을 구성 할 수있는 코 루틴에서 코 루틴을 기다릴 수 있습니다.

if, 루프 및 함수 호출과 같은 코 루틴은보다 자연스러운 방식으로 특정 유용한 패턴 (상태 머신과 같은)을 표현할 수있는 또 다른 종류의 "구조화 된 goto"입니다.


C ++에서 코 루틴의 특정 구현은 약간 흥미 롭습니다.

가장 기본적인 수준에서 C ++ :에 몇 가지 키워드 co_return co_await co_yield와 함께 작동하는 일부 라이브러리 유형을 추가합니다.

함수는 본문에 하나를 포함하여 코 루틴이됩니다. 따라서 선언에서 그들은 함수와 구별 할 수 없습니다.

이 세 키워드 중 하나가 함수 본문에 사용되면 반환 유형 및 인수에 대한 표준 검사가 수행되고 함수가 코 루틴으로 변환됩니다. 이 검사는 함수가 일시 중단 될 때 함수 상태를 저장할 위치를 컴파일러에 알려줍니다.

가장 간단한 코 루틴은 생성기입니다.

generator<int> get_integers( int start=0, int step=1 ) {
  for (int current=start; true; current+= step)
    co_yield current;
}

co_yield함수 실행을 일시 중단하고 해당 상태를에 저장 generator<int>한 다음를 current통해의 값을 반환 합니다 generator<int>.

반환 된 정수를 반복 할 수 있습니다.

co_await한편 코 루틴을 다른 코 루틴에 스플 라이스 할 수 있습니다. 하나의 코 루틴에 있고 진행하기 전에 기다릴 수있는 일 (종종 코 루틴)의 결과가 필요한 경우, 그 결과를 co_await수행합니다. 준비가 되었으면 즉시 진행하십시오. 그렇지 않은 경우 대기중인 대기 가능 항목이 준비 될 때까지 일시 중지합니다.

std::future<std::expected<std::string>> load_data( std::string resource )
{
  auto handle = co_await open_resouce(resource);
  while( auto line = co_await read_line(handle)) {
    if (std::optional<std::string> r = parse_data_from_line( line ))
       co_return *r;
  }
  co_return std::unexpected( resource_lacks_data(resource) );
}

load_data is a coroutine that generates a std::future when the named resource is opened and we manage to parse to the point where we found the data requested.

open_resource and read_lines are probably async coroutines that open a file and read lines from it. The co_await connects the suspending and ready state of load_data to their progress.

C++ coroutines are much more flexible than this, as they were implemented as a minimal set of language features on top of user-space types. The user-space types effectively define what co_return co_await and co_yield mean -- I've seen people use it to implement monadic optional expressions such that a co_await on an empty optional automatically propogates the empty state to the outer optional:

modified_optional<int> add( modified_optional<int> a, modified_optional<int> b ) {
  return (co_await a) + (co_await b);
}

instead of

std::optional<int> add( std::optional<int> a, std::optional<int> b ) {
  if (!a) return std::nullopt;
  if (!b) return std::nullopt;
  return *a + *b;
}

A coroutine is like a C function which has multiple return statements and when called a 2nd time does not start execution at the begin of the function but at the first instruction after the previous executed return. This execution location is saved together with all automatic variables that would live on the stack in non coroutine functions.

A previous experimental coroutine implementation from Microsoft did use copied stacks so you could even return from deep nested functions. But this version was rejected by the C++ committee. You can get this implementation for example with the Boosts fiber library.


coroutines are supposed to be (in C++) functions that are able to "wait" for some other routine to complete and to provide whatever is needed for the suspended, paused, waiting, routine to go on. the feature that is most interesting to C++ folks is that coroutines would ideally take no stack space...C# can already do something like this with await and yield but C++ might have to be rebuilt to get it in.

concurrency is heavily focused on the separation of concerns where a concern is a task that the program is supposed to complete. this separation of concerns may be accomplished by a number of means...usually be delegation of some sort. the idea of concurrency is that a number of processes could run independently (separation of concerns) and a 'listener' would direct whatever is produced by those separated concerns to wherever it is supposed to go. this is heavily dependent on some sort of asynchronous management. There are a number of approaches to concurrency including Aspect oriented programming and others. C# has the 'delegate' operator which works quite nicely.

병렬 처리는 동시성처럼 들리며 관련 될 수 있지만 실제로는 코드의 일부를 실행되고 결과가 다시 수신되는 다른 프로세서로 코드의 일부를 지정할 수있는 소프트웨어와 다소 병렬 방식으로 배열 된 많은 프로세서를 포함하는 물리적 구조입니다. 동 기적으로.

참고 URL : https://stackoverflow.com/questions/43503656/what-are-coroutines-in-c20

반응형