2017-01-20 4 views
1

Node.js 백그라운드에서 비동기식 작업을 수행하기 쉽고 장기 실행 작업을 완료하면 더 많은 작업을 수행 할 수 있으며 그 작업은 Go에서 동일하지만 확실하지는 않습니다. 채널이 어떻게 작동하는지에 대해 머리를 감쌌다.golang에 채널을 잘못 사용하고 있습니까?

나는 경매 데이터 로그의 행을 분석하고 소켓 io를 통해 웹 사이트의 라이브 피드로 스트리밍하기 위해 구문 분석하는 오래된 게임에 대한 파서를 작성합니다. 파일은 한 번에 100 줄을 보낼 수 있고 파서는 한 번에 하나씩 각 줄을 분석하고 각 줄에서 메타 정보를 추출해야합니다 (예 : 항목, 항목 가격 등)

각 단일 줄에는 for 루프가 있습니다 raw := <-itemChannel는 goroutine이 완료 될 때까지 차단하기 위해 루프를 발생시키고 전달하는 것처럼 보인다 (관찰에서) 지금

itemChannel := make(chan Item) 

for _, itemName := range itemList { 
    item := Item { 
     Name: itemName, 
    } 

    // Long running method which does parsing for the item such as pricing, quantity and makes some http calls (runs 75ms on average) 
    go item.FetchData(itemChannel) 

    // Read from the channel when its done 
    raw := <-itemChannel 
    auction.Items = append(auction.Items, raw) 
    auction.Seller = seller 
} 

auctions = append(auctions, auction) 
fmt.Println("Appended auction: ", auction) 
go c.publishToRelayService(auction) 

: (이 항목의 목록이 정규 표현식에서 파생 된 부분을 가정) 반대 실행 데이터가 다시 돌아옵니다 (확실히 item.FetchData(itemChannel)로 실행하는 것은 똑같은 일을합니다.) 데이터가 다시 들어오고 가능한 한 빨리 루프 반복에서 벗어나면 채널에서 어떻게 읽을 수 있습니까? 줄에는 15-20 개의 항목이있어 프로그램이 다음 줄을 파싱하기 전에 2-3 초 동안 중단됩니다. 파서를 가능한 한 빨리 유지하기 위해 다음 라인을 빠져 나가서 빨리 처리 할 수 ​​있기를 바랍니다. 노드의 약속과 비슷한 메커니즘이 있습니까? 여기서는 완료 처리기를 item.FetchData()의 각 완료에 연결할 수 있습니까?

참고fetchChannel은 모든 가져 오기 작업이 완료되면 내 항목 유형 내부에 쓰여집니다.

+0

실전에 실행 가능한 코드를 넣을 수 있습니까? –

+0

질문을 이해하는 것이 더 좋습니다. 실제로 FetchData 메소드에 콜백 함수를 추가하여이 문제를 해결했습니다. 요약하면 채널이 차단됩니다. 그렇다면 왜 우리는 채널을 사용합니까? 서로 다른 시스템에 분산되어있는 동일한 프로그램간에 IPC가 더 많습니까? – Alex

+0

예 채널이 버퍼링되지 않는 한 차단됩니다. –

답변

2

채널의 새 데이터를 기다리고 처리하는 다른 진행 루틴을 작성할 수 있습니다. 이 방법으로 생산자와 소비자가 평행을 실행하고 생산자가 소비자를 생산하는 완료되면 소비자 당신은 소비자가 완료되는 것을 나타 내기 위해 done 채널을 사용할 수있는 빛 공정

있는 그대로 여기에 수행해야합니다

다음은/CSP 채널을 이동하는 Node.js를 움직여 넓은 질문의 관점에서 코드

itemChannel := make(chan Item) 
done := make(chan bool) 
//Consumer 
go func(channel chan Item) { 
    for raw := range channel { 
     auction.Items = append(auction.Items, raw) 
     auction.Seller = seller 
     auctions = append(auctions, auction) 
    } 
    done <- true 
}(itemChannel) 

//Producer 
for _, itemName := range itemList { 
    item := Item{ 
     Name: itemName, 
    } 

    // Long running method which does parsing for the item such as pricing, quantity and makes some http calls (runs 75ms on average) 
    go item.FetchData(itemChannel) 

} 

<-done 
fmt.Println("Appended auction: ", auction) 
go c.publishToRelayService(auction) 
+2

흥미 롭습니다, 이것에 대해 감사드립니다. 그냥 구현하고 트릭을 할 것으로 보인다. 나는 이것이 일을하는 "가는"방법이라고 생각한다. 노드 배경에서 슈퍼 외계인 같습니다 : P – Alex

+1

형제 : D –

1

을 변경할 수있는 방법, 당신은 콜백의 생각을 따로 넣어 시작해야합니다. 필자가 사용한 모든 반응/비동기 패러다임은 사용하기 쉬운 콜백 드레싱의 일부 형식이었습니다. 그러나 CSP는 이렇게하려고하지 않습니다.

Go의 중요한 점은 경량 goroutines의 협업 스케줄링이 운영 체제 스레드와 독립적으로 발생한다는 것입니다. (구현자가 일반적으로 OS 스레드를 통해 가능한 한 CPU 코어를 최대한 활용하려고 노력하지만 후드 속임수). 실제 콜백과 실제 비교는 없습니다.

각 gouroutines에는 독자적인 라이프 사이클이 있습니다. 그것은 꽤 짧을 수 있습니다. 또는 goroutine에 루핑이 포함되어있는 경우 일정 기간 동안 존재할 수 있으며 액터와 유사하게 보일 수 있습니다 (액터 모델에서).

CSP (Communicating Sequential Processes)를 탐구하기 위해 필요한 생각입니다. 디지털 전자 빌딩 블록의 라인을 따라 goroutines을 생각하는 것도 도움이 될 수 있습니다. 게이트 및 와이어는 goroutines 및 채널과 유사합니다.

또한 여러 게이트에서 플립 플롭을 만들 수 있습니다. 동일한 방식으로 내부 채널로 결합 된 '작은'goroutines에서 goroutines을 구성 할 수 있습니다. 이 권리를 얻는다면 '더 큰'goroutine의 외부 채널 만이 공동 작업자에게 우려의 대상이됩니다 (내부 채널이 숨겨져 있음).

이것은 소프트웨어 설계를위한 새로운 방법을 제시하며 Rob Pike가 옹호해온 것들 중 하나입니다 : Concurrency is not Parallelism. 다르게 생각하십시오.

예를 들어 시뮬레이션 소프트웨어 (Conway 's Game of Life)가 더 큰 규모 일 수 있습니다. 저는 각 세포의 개개인 행동을 모델링하여 혈관 내 혈액 흐름과 응고에 대한 매우 강력한 시뮬레이션을 보았습니다. 이 데모에는 4 천만 개의 동시 엔터티가 있으며이 랩톱을 사용하는이 방식이 매우 인상적입니다.

+1

이봐,이게 정말 흥미 롭군요. 필자는 이런 방식으로 소프트웨어를 작성하려고합니다. 여러 시스템에 병렬로 작업을 배포 할 때 이점을 볼 수 있습니다. 이것이 우리에게주는 잠재력은 엄청납니다! 이제 Node와 다른 언어에서 콜백 함수를 전달하는 초자연적 인 느낌이 들었습니다. (비록 동시성을 처리하는 Go의 방법이 단지 동시 적으로 노드의 방식을 뛰어 넘는 이유를 알 수 있지만). Rob Pikes에게도 기사를 읽어 주겠다. 다시 한 번 감사의 말을 전한다. – Alex