작성
·
510
3
안녕하세요 앨런님! 오랜만에 한가지 질문이 있어서 왔습니다~~
그러던 중, 어떤 분이 댓글로 "Serial Queue 에서 하나의 스레드에만 분배된다는 게 '처음 Task를 준 스레드에게 계속해서 준다는 것' 이아니라, '동시에 하나의 Task만 처리되고 있음' 만 보장되는 걸로 알고 있어요. 시리얼 큐에 있는 Task1, Task2, Task3이 동시에 처리되진 않고 하나씩 시리얼하게 처리되되, 모든 Task들이 같은 스레드에서 처리되는 건 보장할 수 없는 거죠."라고 말씀을 주셨습니다. (이곳의 댓글입니당)
좀 더 구글링을 해본 결과 https://stackoverflow.com/questions/51057441/serial-dispatch-queue-will-use-only-one-thread 에서 실제로 같은 serial queue에 들어가는 taks 가 다른 스레드에서도 수행됨을 확인할 수 있었습니다.
결국 "serial queue는 'a' 시간 (특정 Task 실행 시간) 에 하나의 스레드만 사용. 이때 '하나의 스레드'는 '항상 같은 스레드'를 의미하지 않음. 각 태스크가 어느 스레드에서 실행될지 보장되지 않지만, 임의의 '하나의' 스레드가 작업을 수행한다는 것은 보장됨." 이라는 내용을 새롭게 이해했습니다.
혹시 앨런님께서 설명 주신 부분도 위와 같은 내용이었는데, 제가 잘못 이해하고 있었던 부분일까요? 아니면 기존에 이해했던대로 serial queue는 특정한 하나의 스레드만 사용! 이 맞는 내용인데, 제가 새롭게 잘못 알아온걸까요,,??
감사합니다 :)
답변 5
2
네 수진 님! 안녕하세요! 오랜만이시네요!
이 부분에 대해서.. 예전에는
https://www.inflearn.com/questions/65782
위와 같은 방식으로 답변을 드린 적이 있는데,
(그래서 이 내용에 대해서 저도 많은 고민을 한적이 있고...)
제가 예전에 드렸던 답변을 한번 읽어보고 오시면 좋을 것 같긴합니다.
간단하게나마 읽어보셨다는 전제 하에..
위의 질문 / 답변보다 사실 훨씬 더 디테일하고 정확한 말씀드려보자면...
(제가 최근에는 다른 특강들에서는 약간 설명 방식을 다르게 말씀드리기도 하고, 저도 왜 실제 쓰레드 객체를 찍어보면 다르게 나오는지의 이유에 대해서 훨씬 명확하게 정리가 된 것 같기도 해요. 아니 예전에도 위의 질문과 답변을 주고 받으면서 이미 제 머리속에는 결론이 나오기는 했지만, 굳이 이것을 설명할 필요가 있나? 라고 생각하기도 했던 것 같습니다. 별로 중요하지 않다고 생각한 부분도 있는 것 같아요. 저는 개념적으로 사고하는 방식이 더 중요한 것 같아서...)
쨌든, 또 질문이 나오는 걸로봐서, 그리고 수진 님처럼 궁금해하실 수도 있는
다른 분들에게 더이상 논쟁을 만들지 않고 싶어서..
이번에는 제대로 답변을 드려 보려고 합니다.
일단 "소프트웨어적인 쓰레드"는 결국 OS가 관리하는 객체 입니다.
즉, OS는 CPU에 딸린 하드웨어적인 쓰레드를 관리하면서, 객체들을 만들어서 쓰레드 Pool로 관리합니다. 즉, 예를 들어서, 물리적인 쓰레드가 (8코어 16쓰레드라고 가정을 하면) 16개의 쓰레드 밖에 없지만, (누군가 제 수업을 들으셨던 분이 실험을 해보신적이 있는데..) 실제 100개이상 까지도 소프트웨어적인 쓰레드 객체를 만들더라고요.
결국에 OS는 이런 100개이상의 쓰레드 객체를 만들었다가 없애기도 합니다. 즉, 필요할때는 만들고 없애는 것이지요.
개념적으로 위와 같은 그림 이라고 생각하시면 될 것 같습니다. 왼쪽은 실제 물리적인 쓰레드 / 그리고 가운데는 OS가 관리하는 쓰레드 객체 Pool ... 그리고 오른쪽은 실제 우리가 앱을 실행할때 일어나는 일이겠지요. 앱을 실행하면 OS가 관리하는 쓰레드 객체를 가져다가 쓰고, 백그라운드에서 다 사용하면 사실 앱에서는 그 객체가 사라집니다.
그래서 실제로 메인쓰레드가 아닌
제 강의에서 2번, 3번, 4번 쓰레드라고 말씀드리는 쓰레드들은.. 객체이기 때문에 실제로 쓰다가 중간중간 없어졌다가 다시 생겨나는 객체라는 것이 정확하게는 맞습니다.
(제 본 강의에서는 2번, 3번, 4번 쓰레드들이 계속 존재하는 것처럼 설명드리고는 있지만, 실제로는 2, 3, 4번 쓰레드들은 백그라운드 쓰레드 이기 때문에 사용하다가... 필요할때는 없어지고, 필요할때는 다시 쓰레드 풀에서 가져다가 사용하기도 하고 합니다. 굳이 이런 내용까지 다루지 않지만.. 이제 논쟁을 만들고 싶지 않아서 사실 다른 곳에서 특강을 갈때마다 이제는 이런 내용도 꼭 말씀드리고 있어요^^;)
자, 그럼 여기서 어쩌면 감을 잡으셨을 수도 있겠지만,
메인 쓰레드 같은 경우는 앱을 실행하면 당연히 앱 전체를 관리하기 때문에, 메인 쓰레드 객체는 실제로 객체 자체가 절대로 변하지가 않습니다. (동일한 메모리 주소를 가진 인스턴스라는 것이지요.)
다만, 2, 3, 4번,... 등등의 background쓰레드는 객체이기 때문에 변할 수 있습니다. (생성되었다가 사라졌다가...) 시리얼큐가.. 제 강의에서 1개의 쓰레드라고 말씀드리고 있는데... 어쨌든 백그라운드 쓰레드 이기 때문에 실제 객체는 중간의 잠깐의 (일을 안하고) 쉬는 텀이 있으면, 당연히 없어졌다가 (메모리 주소를 찍어보면) 새로운 객체로 교체될 수 있습니다.
그렇기 때문에 당연히 실제로 여러번의 실험을 해보면, 같은 쓰레드 객체로 찍힐때도 있고, 다른 쓰레드 객체로 찍힐때도 있습니다......
그렇다면 결론은? (제 개인적인 의견임을 감안해주세요.)
저는 개인적으로는 시리얼큐를 "한번에 하나씩" 처리하는 큐라고 생각하는 방식이 (오히려) 개념적으로 잘못된 사고체계라고 생각합니다. (그리고 실제로 레이웬더리치나, 미국 친구들도 이론을 설명할때 "한번에 하나씩" 보다는 그냥 "하나의 쓰레드"라고 설명하는 글 / 사고체계가 주류 의견입니다. 그리고 저는 이 의견에 동감하는 편입니다.)
어떤 것을 이론과 개념적으로 바라볼때, 어짜피 앱 단에서 일어나는 일은 어짜피 우리는 백그라운드 쓰레드는 보내는 일을 하는 것 뿐이고 (그 내부는 객체는 어짜피, OS가 알아서 관리하지요.) 그렇다면, 우리가 생각하는 사고 방식은 어떤 방식으로 알고 있어야 할까요?
실제 OS 단에서 일어나는 객체 자체가 다른 것이라고,
(1) 2번 쓰레드 내부 객체가 다른 것이니 그것들을 각각 메모리 주소가 다른 객체라고 인식하고 있어야 할까요? (한번에 하나씩이라고?)
(2) 아니면 그냥 2번 쓰레드라고만 알면 되는 것일까요? (하나의 쓰레드 라고)
저는 후자로 충분하다고 봅니다. (OS가 알아서 잘 관리해주는 데, 내가 내부 객체까지 알아야해(?)..라는 것이 제 의견에 가깝습니다..OS관리 영역은 OS에 맡기고 싶습니다.) 또한 그리고 실제로 앱에서 일어나는 일처리를 제대로 하려고 할때, 오히려 전 1번으로 알고 있는 것이 훨씬 더 큰 방해요소가 된다고 봅니다.
강의 내용에서 잠깐 떠올려보시면 알겠지만, 개념적으로 하나의 쓰레드에서 순서적으로 일어난다고 생각하는 것이 모든 골머리에서 우리의 사고체계를 심플하게 만들어 줄 것이라는 것 잊지않으셨으면 좋겠네요.
저런 댓글이 달린다면, 가볍게 무시하세요.
내가 그걸 몰라서 그렇게 설명하지 않는 것이 아니라고.
좋은 답변이 되시길 바라며.
고맙습니다 :)
1
오호,, 저는 개인적으로 이론적으로 깊게 파고드는걸 좋아해서 오늘 말씀 주신 내용이 다 흥미롭네여 ( o̴̶̷᷅ᴗo̴̶̷᷄ )
물론 앨런님이 처음 시리얼 큐를 설명할 때 "하나의 스레드"를 사용하는 큐가 아닌, 여러개의 스레드 객체를 사용할 수 있되 Task는 "한번에 하나씩" 처리하는 큐라고 했으면 개념이 명확히 잡히지 않았을 것 같긴 합니다. (네,,,,,,,,머라구요,,????🤔 하면서 강의를 들었겠죠,,??)
하지만 시리얼 큐에 대한 이해를 한차례 하고 나서 실제로 OS 단에서는 어떻게 돌아간다! 는 사실을 접하니 개념과 실제 동작을 알게 된 것 같아 좋네용
오늘도 감사합니다~!
1
네네 수진 님이 이해하신 대로
MainThread를 제외한 나머지 스레드 객체는 사용할 때만 잠깐 생성되었다가 사라지기 때문에... 즉, 시리얼 큐라도 중간에 사용하는 스레드 객체가 변경될 수 있다는 것이죠. 그래서 어짜피 우리는 앱단에서 관리하고 있는 것이니 시리얼 큐는 하나의 스레드를 사용하는 것처럼 이해를 해야하는 것이고(내부에서 실제 객체는 변할 수 있지만), 개념적으로 그렇게 알고 있는 것이 실제 OS단이 아닌 앱단의 관점에서는 더 맞는 관점일라고 보인다는 것이죠.
위의 링크는 무시하셔도 좋을 것 같습니다.
링크가 더 예전 답변이고, 그 내용을 제가 더 디테일하게 표현하려다가 지금 처럼 명확하게 표현하지 못한 것 같아요. (그냥 예전에 동일한 질문이 있었다는 차원에서 생각해보시면 될 것 같아요.)
1.번에 대해서는 가능성에 대해서 말씀드린 부분이예요. 우리는 알수가 없지만, OS가 알아서 관리하는 부분이기 때문에, 저는 "하드웨어적인 여러개의 쓰레드"라고 말씀드린 부분은 그냥 무시하셔도 좋을 것 같고. 아니면, 제가 소프트웨어적인 쓰레드 Pool관점에서, 저 당시에는 더 명확하게 표현하지 못한것 같아요. (실제로 하나의 객체라면 물리적인 쓰레드도 1개가 맞을 것 같긴하지만, 어짜피 내부 OS구조를 우리가 알 수 있는 것도 아니고, 중요한 것도 아니다라는 관점에서 보시면 될 것 같습니다.)
2. 1번 답변과 유사한 것 같아요. 제가 예전 글을 조금 표현을 못해서 잘 못 썼다고 생각하셔도 좋을 것 같고, 어짜피 OS의 관리 영역이기 때문에, 모든 것을 우리가 알 수 없다는 관점의 가능성에 대해서 말씀드린 것 뿐입니다. (물론 CS를 더 공부하게된 지금의 입장에서 뇌피셜로는 메인쓰레드의 경우 1개의 물리쓰레드가 관여 하는 것이 훨씬 효율적이기 때문에 그렇게 동작하는 방식에 가깝다고 생각이 들지만, 어짜피 우리가 관여해서 생각할 부분이 아니다라는 관점은 변하질 않는 것 같습니다. 저는 중요하지 않다고 봐요.)
고맙습니다.
1
상세한 답변 감사합니다. 결국 MainThread를 제외한 나머지 스레드 객체는 사용할 때만 잠깐 생성되었다가 사라짐. 즉, 시리얼 큐라도 중간에 사용하는 스레드 객체가 변경될 수 있음. 하지만 시리얼 큐는 하나의 스레드 객체를 사용하는 것처럼 설명을 하는 것이 이해에 훨씬 직관적이기 때문에 그렇게 설명해 주신것. 이 되겠네욤
답변 주신 것을 읽고, 원래 처음에 링크 주신 답변을 한번 더 읽어봤는데 이때 말씀 중 두가지 헷갈리는 부분이 있습니다.
1. 위의 링크를 붙여주신 것과 같이 실제로는 한번에 하나의 쓰레드를 사용하는 것이 맞습니다. 그게 실제로는 하드웨어적인 여러개의 쓰레드 일수도 있겠지요.
-> 여기서 하드웨어적인 여러개의 쓰레드를 언급해주신 것은, “소프트웨어적인 여러개의 스레드를 쓸 수 있는 것은 당연하고, 해당 스레들이 심지어 다른 물리 스레드에 속하는 애들일 수도 있다”의 의미를 담고 있는건가요?
2. 앱을 실행할때 특정하는 메인쓰레드조차도, 어쩌면 하드웨어적으로 여러쓰레드를 사용할지도 모릅니다. 하지만, 아무도 메인쓰레드가 한번에 하나의 쓰레드를 사용하는 개념이라고 생각하지 않지요..)
-> 제가 드린 질문의 답변에서는 “메인 쓰레드 객체는 실제로 객체 자체가 절대로 변하지가 않습니다. (동일한 메모리 주소를 가진 인스턴스라는 것이지요.)” 라고 말씀주셨는데, 저 글의 답변에서는 메인 스레드 객체마저 변할 수 있는 것으로 해석됩니다. 혹시 메인스레드조차 하드웨어적으로 여러 스레드를 사용할 수 있다는 의미가 어떤 뜻인지 조금 더 설명 부탁드려도 될까요?
0