delay와 TimeSpan을 써서 일정 시간 이후에 실행되도록 하면 어느 정도 오차가 생기잖아
이건 정해진 시간에 주도권을 바로 잡기 어려워서 생기는 거라고 이해를 했는데 delayframe은 그 프레임이 지나면 무조건 실행이 되는 것 같더라고
task의 동작 방식이 매 프레임마다 모든 task를 확인하고 조건이 맞으면 실행하는 그런 방식인 건가?
그래서 delay time은 오차가 생기고 frame은 그 프레임에 바로 실행이 되는 거고?
delay와 TimeSpan을 써서 일정 시간 이후에 실행되도록 하면 어느 정도 오차가 생기잖아
이건 정해진 시간에 주도권을 바로 잡기 어려워서 생기는 거라고 이해를 했는데 delayframe은 그 프레임이 지나면 무조건 실행이 되는 것 같더라고
task의 동작 방식이 매 프레임마다 모든 task를 확인하고 조건이 맞으면 실행하는 그런 방식인 건가?
그래서 delay time은 오차가 생기고 frame은 그 프레임에 바로 실행이 되는 거고?
task가 어느 맥락에서 task를 말하는건지 모르겠지만 비동기 프로그래밍에서의 task는 주도권을 주고받는 거임 task를 만든 순간에 실행되는게 아니라 await를 했을 때 실행됨. Delay를 거는 건 일반적으로 task 위로 새로운 태스크가 만들어져서 100프레임 기다린 뒤 선택된 task를 실행(await)함.
그러면 실행할 task는 어떻게 정해지는 거임? 싱글 스레드에서 여러 task가 있을 때 어떻게 정해지는 거지
Unitask의 경우, 구현을 확인해보니 TaskTracker가 있어서 얘가 매번 검사해주는 듯. C# Task도 뭐 대충 비슷한 게 있을 것 같음
보통 비동기 프로그래밍은 태스크풀이라는 큐같은게 있어서 거기에 쌓임. 싱글쓰레드가 실행하다 await를 하는 타이밍에 큐에 쌓인 태스크들을 하나씩 처리하는 구조임
그러면 테스크풀에 조건에 맞는 테스크들이 집어넣어지고 일정 단위(프레임이나 cpu클럭 등)마다 실행한다는 것?
코드 어딘가에서 await를 할 때 실행함. 그래서 await를 안하고 CPU를 무식하게 많이 쓰는 task가 있으면 다른 task가 안 돌아가는 꼴을 볼 수 있음. 유니티의 경우 싱글 쓰레드라는 가정하에 프레임 처리를 하고나서 쉬는시간에 짬짬히 task를 돌릴듯
그럼 마지막 await은 누가 실행시켜주는 거임? 코드 어딘가에서 await을 해야 다른 task들이 돌아갈 수 있으면 마지막으로 await된 task는 돌아갈 수 없는 거 아녀?
await 말고도 return도 주도권을 넘겨주는 거임. task가 종료하면서 주도권 넘기고 스케쥴러 판단하에 다른 태스크를 실행할지 아니면 다음 프레임을 돌릴지 정함
아 여기서 말하는 return은 그냥 함수의 리턴이 아니라 task의 리턴임
ㄳㄳ 많이 도움됐음 이런 정보는 어디서 얻은 거임?
지금은 퇴사하긴 했지만 서버 프로그래머라서 쓰레드 최적화 많이 하고 다녀서 비동기/병렬 프로그래밍에 빠삭함. 쓰레드가 막히면 터지는게 서버라서..
실전으로 배웠구나ㅋㅋ... 알려줘서 ㄳㄳ
c# 기본 task는 그냥 스타트하면 시작하는거 아냐? os가 알아서 코어에 배분해서 동시처리하던데
기본 task가 아닌 UniTask긴 한데 await을 하면 시간은 오차가 생기고 프레임은 오차가 없어 보여서 await이 어떻게 이루어지는지 궁금했음
unitask에서 시간도 코루틴 waitforseconds처럼 프레임마다 검사함 0.001초 대기 후 실행 이렇게 해도 다음 프레임이 되야 실행됨.
그래서 unitask랑 코루틴의 delaytime은 오차가 있는 거겠네 ㄳㄳ
그러면 unitask가 아닌 task도 같나?
task는 운영체제에서 돌아가는 거니 cpu 클럭이든 운영체제에서 프로그램 실행하는 단위같은거에 따라 정해지지 않을까?
아 코루틴이나 unitask는 유니티에 맞춰진 거니까 프레임 따라가는 거고 task는 c#에 맞춰진 거니 다르겠네 ㄳㄳ 해결됐다
c#에서 task를 사용하면 스레드풀에 task를 분배해서 비동기로 실행됨. 근데 c#에 SynchronizationContext를 커스터마이징하면 task실행방식을 네가 정할 수 있음. 그래서 유니티는 직접 synchronizationcontext를 만들어서 모든 task가 메인스레드에서만 돌게 해놨음. 애내도 언급해놨어
https://docs.unity3d.com/kr/2020.3/Manual/overview-of-dot-net-in-unity.html
맨밑에글에
써있음
비동기 아닌 비동기.. 유니티에 스레드 풀이 있다고 봤는데 유니티 api에 해당되지 않는 작업들만 스레드 풀이랑 같이 쓰면 멀티스레딩이 되긴 하는 거임? 아니면 글처럼 안 되나
정확하게 말하면 C#코드에서 SynchronizationContext.current가 null이면, 너가 async함수를 호출하는 즉시 c#에서는 Threadpool에 알아서 Task를 분배해서 비동기(다른 스레드)에서 돌아갈거임. 근데 유니티는 SynchronizationContext.current에 UnitySynchronizationContext를 만들어서 넣어뒀거든. 저렇게 넣어두면 async함수를 호출해도 UnitySynchronizationContext를 이용해서 메인스레드에서 돌아가게됨. async함수호출시 디폴트 기능을 바꾼거기때문에 너가 원하는 비동기를 하려면 다른방식을 써야할거야
내가볼때 Task.Run(()=>asyncFunction()) 하면 별도의 스레드에서 돌아갈 걸로 예상된다. 번거롭지만 어쩔수가 없음. 한번 그냥 async호출이랑, Task.Run호출해서 현재 threadID를 출력을 해봐. 그럼 얘가 다른스레드에서 돌아가는지 알수있음
ㄳㄳ 서버도 데디케이트라 굳이 멀티스레딩 안 쓸 것 같긴 한데 이후에 쓸 일 있으면 봐야겠음