•
채널- 코루틴 간 공유 메모리 동기화 문제 해결
◦
코루틴 간 안전한 데이터 통신 - 메모리 주소가 아니라 메시지 사용
◦
상태 공유에 따른 교착 상태 진입, 일관성 상실 등을 방지
▪
데드락
▪
레이스 컨디션
▪
원자성 위반
◦
채널 활용 사례
▪
스트리밍 데이터
•
다수 데이터 소스로부터 네트워크 데이터 요청 / 수신
•
데이터 소스별 응답성 차이
•
awaitAll의 경우 가장 늦은 응답에 맞춰 동기화
•
채널로 상태 변경 경로를 단일화하고, 데이터 소스별로 응답이 올때마다 메시지로 전달
•
멀티 프로듀서, 싱글 컨슈머 (이벤트 디스패칭 방식)
▪
분산 작업
•
네트워크 데이터 요청 + 연산
•
네트워크 요청 시간 : 데이터 연산의 소요 시간 = 1 : 2
•
네트워크 요청 쓰레드 : 데이터 연산 쓰레드 = 1 : 2
•
채널로 네트워크 요청을 통해 가져온 데이터를 데이터 연산 쓰레드로 안전하게 전달
•
멀티 프로듀서, 멀티 컨슈머
◦
채널 유형
▪
채널에 여러 유형이 존재 하는 이유
•
프로듀서와 컨슈머의 속도 차이의 정도와 대응 방식이 다름
•
컨슈머가 처리할 수 있는 이상으로 프로듀셔가 생산하는 경우 문제 발생(OOM, RateLimit 등)
▪
언버퍼드 채널
•
버퍼가 없음
•
receive로 소비할 때 비로소 send로 생산
▪
버퍼드 채널
•
LinkedListChannel (무한)
•
ArrayChannel (유한)
•
ConflatedChannel (덮어쓰기)
•
활용예
override fun onCreate(savedInstanceState: Bundle?) {
...
GlobalScope.launch {
loadMore()
}
}
JavaScript
복사
private suspend fun search() {
val query = findViewById<EditText>(R.id.searchText)
.text.toString()
val channel = searcher.search(query)
while (!channel.isClosedForReceive) {
val article = channel.receive()
GlobalScope.launch(Dispatchers.Main) {
viewAdapter.add(article)
}
}
}
JavaScript
복사
class Searcher {
private val dispatcher = newFixedThreadPoolContext(3, "IO")
private val factory = DocumentBuilderFactory.newInstance()
private val feeds = listOf(
Feed("npr", "https://www.npr.org/rss/rss.php?id=1001")
Feed("cnn", "http://rss.cnn.com/rss/cnn_topstories.rss"),
Feed("fox", "http://feeds.foxnews.com/foxnews/latest?format=xml")
)
fun search(query: String) : ReceiveChannel<Article> {
val channel= Channel<Article>(150)
feeds.forEach { feed ->
GlobalScope.launch(dispatcher) {
search(feed, channel, query)
}
}
return channel
}
private suspend fun search(feed: Feed,
channel: SendChannel<Article>,
query: String) {
val builder = factory.newDocumentBuilder()
val xml = builder.parse(feed.url)
val news = xml.getElementsByTagName("channel").item(0)
Log.d("Searcher", "Looking for $query")
(0 until news.childNodes.length)
.map { news.childNodes.item(it) }
.filter { Node.ELEMENT_NODE == it.nodeType }
.map { it as Element }
.filter { "item" == it.tagName }
.forEach {
val title = it.getElementsByTagName("title")
.item(0)
.textContent
var summary = it.getElementsByTagName("description")
.item(0)
.textContent
if (title.contains(query) || summary.contains(query)) {
if (summary.contains("<div")) {
summary = summary.substring(0, summary.indexOf("<div"))
}
val article = Article(feed.name, title, summary)
channel.send(article)
}
}
}
}
JavaScript
복사