SlideShare a Scribd company logo
1 of 46
Download to read offline
유니티 iOS에서 LINQ 사용하기
내 코드가 이렇게 간결할 리 없어
넥슨 지티
김대희
발표자
김대희 게임 프로그래머 4년 차
선데이토즈, 넥슨 코리아를 거쳐
현재 넥슨 지티에서 신규 모바일 게임 제작 중
뭐가 문제에요?
유니티에서 LINQ를 쓰고 싶어요.
LINQ
Language-Integrated Query
데이터 저장소 종류와 관계 없이 저장소에 일관성 있는 인터페이스로 질의
LINQ to Objects, LINQ to SQL, LINQ to XML ...
본 세션에서는 LINQ to Objects 관련 내용만을 다룹니다.
LINQ
int[] numbers = { 5, 10, 8, 3, 6, 12 };
Query syntax
var results = from num in numbers
where num % 2 == 0
orderby num
select num * 2;
foreach(var result in results)
Console.WriteLine(result);
Method syntax
var results = numbers
.Where(num => num % 2 == 0)
.OrderBy(num => num)
.Select(num => num * 2);
foreach(var result in results)
Console.WriteLine(result);
LINQ 사용 예시
정말 간결할까요?
기획서의 요구사항
1) 퀘스트들의 제목을 출력해주세요.
2) 입장한 맵에 해당되는 퀘스트들만 보여줍니다.
3) 현재 진행 중이어야 하고요.
4) 진행 상태가 높은 퀘스트를 가장 먼저 출력합니다.
5) 진행 상태가 같은 경우 퀘스트 아이디가 낮은 순서로 출력합니다.
기획서의 요구사항
List<Quest> results = new List<Quest>();
foreach (Quest quest in quests)
{
if (quest.IsActive)
{
if (quest.MapIndex == currentMapIndex)
results.Add(quest);
}
}
results.Sort((x, y) =>
{
int compareValue = y.Progress.CompareTo(x.Progress);
if (compareValue == 0)
return x.ID.CompareTo(y.ID);
return compareValue;
});
foreach (Quest quest in results)
Console.WriteLine(quest.Title); Non LINQ
기획서의 요구사항
var results = quests
.Where(quest => quest.IsActive)
.Where(quest => quest.MapIndex == currentMapIndex)
.OrderByDescending(quest => quest.Progress)
.ThenBy(quest => quest.ID);
foreach (Quest quest in results)
Console.WriteLine(quest.Title);
참 쉽죠?
LINQ
LINQ
동일한 인터페이스 사용 - 모든 컬렉션 류, 그 외 다른 종류의 저장소에도 동일함.
다양하고 편리한 기능 - Max, Min, Average, OrderBy, First, FirstOrDefault, Last, LastOrDefault …
지연 실행 - 성능 이점
간결한 High Level 코드 품질 - 유지 보수 용이
컴파일 타임 에러 체크 – SQL 시 문자열 쿼리의 체크를 컴파일 타임에 가능
LINQ
LINQ는 느리다?
LINQ (to Objects)는 충분히 빠르다
LINQ
Galaxy S3 100개 1,000개 10,000개 100,000개
Non LINQ 0 ms 0 ms 4 ms 42 ms
LINQ 0 ms 2 ms 26 ms 250 ms
iPhone 6+ 100개 1,000개 10,000개 100,000개
Non LINQ 0 ms 0 ms 3 ms 16 ms
LINQ 0 ms 1 ms 10 ms 37 ms
‘기획서의 요구사항’ 성능 테스트
LINQ
디바이스 성능은 계속 발전
- 차이가 점점 좁혀진다.
80-20 법칙
- 최적화가 필요한 곳만 코드를 풀어 쓰자
클라이언트 사이드에서 대용량의 데이터를 사용하는 곳은 많지 않다.
- 100,000개의 요소를 가진 컬렉션은 거의 없다.
왜 못썼나요?
지금부터 살펴 봅시다.
LINQ on iOS
List<string> strs = new List<string> { “0”, “1”, “2”, “3” };
string first = strs.FirstOrDefault ();
Debug.Log(first); // “0"
문제 없음
LINQ on iOS
List<int> numbers = new List<int> { 0, 1, 2, 3 };
int first = numbers.FirstOrDefault ();
Debug.Log(first.ToString());
ExecutionEngineException: Attempting to JIT compile method
'System.Linq.Enumerable/PredicateOf`1<int>:.cctor ()' while running with --aot-only.
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for
PredicateOf`1
LINQ on iOS
LINQ 코드는 System.Core.dll에 존재하여 디버깅도 못해보고
많은 Unity 사용자들은 LINQ 사용을 포기
Analyzation
LINQ 소스가 있는 System.Core.dll를 디컴파일
앞서 문제가 있었던 FirstOrDefault 메소드 관련 부분만 발췌
public static class Enumerable
{
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
return First (source, PredicateOf<TSource>.Always, Fallback.Default);
}
private static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, Fallback fallback)
{
foreach (TSource source1 in source)
{
if (predicate(source1))
return source1;
}
if (fallback == Fallback.Throw)
throw new InvalidOperationException();
return default(TSource);
}
private enum Fallback
{
Default,
Throw,
}
private class PredicateOf<T>
{
public static readonly Func<T, bool> Always = (t => true);
}
}
IEnumerable<int> source
Func<int, bool> predicateIEnumerable<int> source
PredicateOf<int>.Always 이 녀석이 문제
public static class Enumerable
{
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
return First (source, PredicateOf<TSource>.Always, Fallback.Default);
}
private class PredicateOf<T>
{
public static readonly Func<T, bool> Always = (t => true);
}
…
}
예외가 발생하지 않는다.
void _unusedMethod() // type hint, 해당 메소드는 어디서도 호출 되지 않습니다.
{
new PredicateOf<int>();
}
C# 실행 환경
C#
Source Code
IL
(Intermediate
Language)
Machine Code
C# Compiler JIT Compiler
RuntimeCompile time
C#
Source Code
IL
(Intermediate
Language)
Machine Code
C# Compiler AOT Compiler
Compile time
JIT
AOT iOS에서의 구동환경
Mono AOT Limitations
Generic 과 관련하여 특정 상황에서
Generic Type Parameter가 Value Type일 때 한계를 보임
Generic Type Parameter
List<int>, List<string>, List<float>
위 세 타입은 전부 다른 타입
각기 다른 타입이기에 전부 다른 Machine Code를 생성해야 하지만...
Generic Code Explosion
Generic Type Parameter마다 각기 다른 타입에 대해
Machine Code를 생성하게 되면 코드 양 급증
성능에 부정적인 영향
Generic Sharing
List<int>
List<int>.Add
List<int>.Remove
List<float>
List<float>.Add
List<float>.Remove
List<string>
List<string>.Add
List<string>.Remove
List<File>
List<File>.Add
List<File>.Remove
Value Type Reference Type
구현에 따라 몇 몇 Value Type은 공유 될 수도 있다. ex) int, enum
Generic Sharing
AOT의 Generic Type Parameter가 Value Type일 때만
문제가 발생하는 이유는 이와 같이 다른 메커니즘을 지니기 때문
또한 상대적으로 Reference Type에 비해 Value Type은
Generic Type Parameter 마다 코드를 생성해야 하기 때문에
AOT의 경우 코드가 누락될 가능성이 생김.
이 페이지의 내용은 발표자의 가설입니다.
Exception
ExecutionEngineException: Attempting to JIT compile method
'System.Linq.Enumerable/PredicateOf`1<int>:.cctor ()' while running with --aot-only.
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for
PredicateOf`1
System.Linq.Enumerable/PredicateOf<int>의 Class Constructor(cctor) 메소드를 찾을 수 없어
JIT Compile를 시도하다가 난 예외
Exception
몇 몇 복잡한 상황에서 AOT 컴파일러가 Generic 타입을 캐치하지 못한 채 실행 파일을 생성.
따라서 이전에 언급한 구체적인 타입에 대한 힌트를 주게 되면 AOT 컴파일러는 해당 타입에
대한 코드를 미리 생성 가능.
void _unusedMethod() // type hint
{
new PredicateOf<int>();
}
LINQ in Mono 3.x
#if !FULL_AOT_RUNTIME
private class PredicateOf<T>
{
public static readonly Func<T, bool> Always = (Func<T, bool>)(t => true);
}
#endif
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
#if !FULL_AOT_RUNTIME
return First<TSource>(source, PredicateOf<TSource>.Always, Fallback.Default);
#endif
foreach(var element in source)
return element;
return default(TSource);
}
Mono 3.x는 해당 버그를 우회했다.
유니티는 Mono 2.x를 사용
그 외…
몇 몇 메소드의 경우 특정 상황에서 Lambda 또는 익명 메소드를 AOT 컴파일 하지 못한다.(Generic과 무관)
해당 Lambda 또는 익명 메소드를 멤버 메소드로 바꾸면 예외가 사라진다.
public static double Average (this IEnumerable<int> source, Func<TSource, int> selector)
{
return source.Select(selector).Average<int, long, double> (source, (a, b) => a + b, (a, b) => (double) a / (double) b);
}
public static double AverageModified(this IEnumerable<int> source, Func<TSource, int> selector)
{
return source.Select(selector).Average<int, long, double> (source, Func1, Func2); // Lambda를 멤버 메소드로 대체
}
static long Func1(long a, int b)
{
return a + b;
}
static double Func2(long a, long b)
{
return (double)a / (double)b;
}
실제 발표 시 해당 페이지의 일부 내용이 잘못 표기 되어 수정되었습니다.
이 메소드 내부에 사용한 람다식의 코드를
생성하지 못한다.
ex> Action action = () => Debug.Log(“Foo”);
action();
그 외…
그 외에도 여러 가지 패턴의 AOT 관련 예외가 있으며 자세한 사항은 아래의 링크에서 확인.
- http://neue.cc/2014/07/01_474.html
LINQ Exception
iOS 환경에서 LINQ를 사용할 수 없는 이유는 LINQ 자체의 결함이 아니라
mono AOT 컴파일러의 버그가 원인
그럼 어떻게 해야 하나요?
지금까지 내용은 다 잊어도 좋습니다.
지금부터 내용은 잊으면 안 됩니다.
Third party library
UniLinq
- Mono 3.10.0의 LINQ 코드를 기반
- 307개의 유닛테스트
- using UniLinq;
- https://github.com/RyotaMurohoshi/UniLinq
IL2CPP
Unity Technology에서 만든 AOT 기술.
iOS 64bit 지원
현재 최신 버전의 IL2CPP는 안정적으로 LINQ를 지원(ver. 5.2.1f 에서 확인)
IL2CPP vs Mono AOT
C#
Source Code
IL
(Intermediate
Language)
C# Compiler
IL2CPP
AOT Compiler
Compile time
C++
Source Code
Machine Code
C++ Compiler
C#
Source Code
IL
(Intermediate
Language)
Machine Code
C# Compiler AOT Compiler
Compile timeMono AOT
IL2CPP
LINQ with IL2CPP
// Test.cs
public class Test : MonoBehaviour
{
void Start ()
{
List<int> intList = new List<int> () { 0, 1 };
intList.FirstOrDefault ();
List<float> floatList = new List<float> { 0, 1 };
floatList.FirstOrDefault ();
List<string> stringList = new List<string>{ "0", "1" };
stringList.FirstOrDefault ();
List<Material> materialList = new List<Material> ();
materialList.FirstOrDefault ();
}
}
LINQ with IL2CPP
// Bulk_Generics_3.cpp
// System.Collections.Generic.List`1<System.Int32>
struct List_1_t3644373756;
// System.Collections.Generic.List`1<System.Object>
struct List_1_t1634065389;
// System.Collections.Generic.List`1<System.Single>
struct List_1_t1755167990;
List<string> methods
List<Material> methods Shared
string, Material은 Reference Type
int(Int32), float(Single)은 Value Type
LINQ with IL2CPP
// GenericMethods0.cpp
// TSource System.Linq.Enumerable::FirstOrDefault<System.Int32>(System.Collections.Generic.IEnumerable`1<TSource>)
extern "C" int32_t Enumerable_FirstOrDefault_TisInt32_t2847414787_m1700521655_gshared (Il2CppObject * __this /* static,
unused */, Il2CppObject* ___source, const MethodInfo* method)
{
{
Il2CppObject* L_0 = ___source;
Check_Source_m228347543(NULL /*static, unused*/, (Il2CppObject *)L_0, /*hidden argument*/NULL);
Il2CppObject* L_1 = ___source;
IL2CPP_RUNTIME_CLASS_INIT(IL2CPP_RGCTX_DATA(method->rgctx_data, 0));
Func_2_t3308141622 * L_2 = ((PredicateOf_1_t2617073743_StaticFields*)IL2CPP_RGCTX_DATA(method->rgctx_data,
0)->static_fields)->get_Always_0();
int32_t L_3 = (( int32_t (*) (Il2CppObject * /* static, unused */, Il2CppObject*, Func_2_t3308141622 *, int32_t, const
MethodInfo*))IL2CPP_RGCTX_METHOD_INFO(method->rgctx_data, 1)->method)(NULL /*static, unused*/, (Il2CppObject*)L_1,
(Func_2_t3308141622 *)L_2, (int32_t)0, /*hidden argument*/IL2CPP_RGCTX_METHOD_INFO(method->rgctx_data, 1));
return L_3;
}
}
LINQ with IL2CPP
PredicateOf_1_t2617073743_StaticFields
get_Always_0
,
LINQ with IL2CPP
// Enumerable.cs 원본 PredicateOf
private class PredicateOf<T>
{
public static readonly Func<T, bool> Always = (t => true);
}
LINQ with IL2CPP
// System_Core_System_Linq_Enumerable_PredicateOf_1_ge108692892.h
// System.Linq.Enumerable/PredicateOf`1<System.Int32>
struct PredicateOf_1_t2617073743 : public Il2CppObject
{
public:
public:
};
LINQ with IL2CPP
// System_Core_System_Linq_Enumerable_PredicateOf_1_ge108692892.h
// System.Func`2<System.Int32,System.Boolean>
struct Func_2_t3308141622;
struct PredicateOf_1_t2617073743_StaticFields
{
public:
// System.Func`2<T,System.Boolean> System.Linq.Enumerable/PredicateOf`1::Always
Func_2_t3308141622 * ___Always_0;
// System.Func`2<T,System.Boolean> System.Linq.Enumerable/PredicateOf`1::<>f__am$cache1
Func_2_t3308141622 * ___U3CU3Ef__amU24cache1_1;
…
public:
inline Func_2_t3308141622 * get_Always_0() const { return ___Always_0; }
…
}
LINQ with IL2CPP
// Bulk_Generics3.cpp
// System.Void System.Linq.Enumerable/PredicateOf`1<System.Int32>::.cctor()
extern "C" void PredicateOf_1__cctor_m686174972_gshared (Il2CppObject * __this /* static, unused */, const MethodInfo* method)
{
…
}
// System.Boolean System.Linq.Enumerable/PredicateOf`1<System.Int32>::<Always>m__76(T)
extern "C" bool PredicateOf_1_U3CAlwaysU3Em__76_m1746297546_gshared (Il2CppObject * __this /* static, unused */, int32_t ___t,
const MethodInfo* method)
{
{
return (bool)1;
}
}
Mono AOT로 컴파일되 지 않았던 메소드가
잘 생성이 되어 있는 걸 알 수 있다.
결론
IL2CPP를 사용. (iOS 64bit 지원을 위해서는 반드시 사용)
만약 낮은 버전의 Unity를 사용해야 한다면 Third party library 사용
그래도 뭔가 찜찜하고 불안하면 IL2CPP에서도 소스 코드 수정이 가능한 Third party library 사용
사실 Unity에서 LINQ를 사용하지 못한다는 편견을 깨고 싶었습니다.
감사합니다.

More Related Content

What's hot

Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)
Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)
Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)Esun Kim
 
[Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용
[Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용 [Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용
[Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용 MinGeun Park
 
NHN NEXT 게임 전공 소개
NHN NEXT 게임 전공 소개NHN NEXT 게임 전공 소개
NHN NEXT 게임 전공 소개Seungmo Koo
 
[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기MinGeun Park
 
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기현철 조
 
실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략YEONG-CHEON YOU
 
Custom SRP and graphics workflows - Unite Copenhagen 2019
Custom SRP and graphics workflows - Unite Copenhagen 2019Custom SRP and graphics workflows - Unite Copenhagen 2019
Custom SRP and graphics workflows - Unite Copenhagen 2019Unity Technologies
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개MinGeun Park
 
그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...
그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...
그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...ozlael ozlael
 
[NDC 2009] 행동 트리로 구현하는 인공지능
[NDC 2009] 행동 트리로 구현하는 인공지능[NDC 2009] 행동 트리로 구현하는 인공지능
[NDC 2009] 행동 트리로 구현하는 인공지능Yongha Kim
 
임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012devCAT Studio, NEXON
 
Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1YEONG-CHEON YOU
 
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019devCAT Studio, NEXON
 
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술
Ndc2010 전형규   마비노기2 캐릭터 렌더링 기술Ndc2010 전형규   마비노기2 캐릭터 렌더링 기술
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술henjeon
 
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019devCAT Studio, NEXON
 
ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템
ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템
ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템Chaeone Son
 
임태현, 게임 서버 디자인 가이드, NDC2013
임태현, 게임 서버 디자인 가이드, NDC2013임태현, 게임 서버 디자인 가이드, NDC2013
임태현, 게임 서버 디자인 가이드, NDC2013devCAT Studio, NEXON
 
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술Ki Hyunwoo
 
R2서버정진욱
R2서버정진욱R2서버정진욱
R2서버정진욱jungjinwouk
 
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019devCAT Studio, NEXON
 

What's hot (20)

Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)
Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)
Akka.NET 으로 만드는 온라인 게임 서버 (NDC2016)
 
[Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용
[Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용 [Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용
[Unite17] 유니티에서차세대프로그래밍을 UniRx 소개 및 활용
 
NHN NEXT 게임 전공 소개
NHN NEXT 게임 전공 소개NHN NEXT 게임 전공 소개
NHN NEXT 게임 전공 소개
 
[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기
 
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
[NDC17] Unreal.js - 자바스크립트로 쉽고 빠른 UE4 개발하기
 
실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략
 
Custom SRP and graphics workflows - Unite Copenhagen 2019
Custom SRP and graphics workflows - Unite Copenhagen 2019Custom SRP and graphics workflows - Unite Copenhagen 2019
Custom SRP and graphics workflows - Unite Copenhagen 2019
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개
 
그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...
그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...
그래픽 최적화로 가...가버렷! (부제: 배치! 배칭을 보자!) , Batch! Let's take a look at Batching! -...
 
[NDC 2009] 행동 트리로 구현하는 인공지능
[NDC 2009] 행동 트리로 구현하는 인공지능[NDC 2009] 행동 트리로 구현하는 인공지능
[NDC 2009] 행동 트리로 구현하는 인공지능
 
임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012임태현, MMO 서버 개발 포스트 모템, NDC2012
임태현, MMO 서버 개발 포스트 모템, NDC2012
 
Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1
 
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019
 
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술
Ndc2010 전형규   마비노기2 캐릭터 렌더링 기술Ndc2010 전형규   마비노기2 캐릭터 렌더링 기술
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술
 
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
 
ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템
ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템
ndc 2017 어쩌다 신입 - 초보 게임 개발자 2년 간의 포스트모템
 
임태현, 게임 서버 디자인 가이드, NDC2013
임태현, 게임 서버 디자인 가이드, NDC2013임태현, 게임 서버 디자인 가이드, NDC2013
임태현, 게임 서버 디자인 가이드, NDC2013
 
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술
 
R2서버정진욱
R2서버정진욱R2서버정진욱
R2서버정진욱
 
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019
 

Similar to [NDC 2016] 유니티, iOS에서 LINQ 사용하기

Lecture 1: Introduction to Python and TensorFlow
Lecture 1: Introduction to Python and TensorFlowLecture 1: Introduction to Python and TensorFlow
Lecture 1: Introduction to Python and TensorFlowSang Jun Lee
 
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)Dong Chan Shin
 
I phone 2 release
I phone 2 releaseI phone 2 release
I phone 2 releaseJaehyeuk Oh
 
Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료
Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료
Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료SeongTae Jeong
 
NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서
NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서
NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서tcaesvk
 
Hoons 닷넷 정기세미나
Hoons 닷넷 정기세미나Hoons 닷넷 정기세미나
Hoons 닷넷 정기세미나병걸 윤
 
Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015Kris Jeong
 
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C#  혼합 멀티플랫폼 게임 아키텍처 설계[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C#  혼합 멀티플랫폼 게임 아키텍처 설계
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계Sungkyun Kim
 
불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 명신 김
 
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019min woog kim
 
[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...
[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...
[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...Seok-joon Yun
 
20201121 코드 삼분지계
20201121 코드 삼분지계20201121 코드 삼분지계
20201121 코드 삼분지계Chiwon Song
 
C# Game Server
C# Game ServerC# Game Server
C# Game Serverlactrious
 
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기Jaeseung Ha
 
About Visual C++ 10
About  Visual C++ 10About  Visual C++ 10
About Visual C++ 10흥배 최
 
Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택JinTaek Seo
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features SummaryChris Ohk
 
니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트효준 강
 
코드 생성을 사용해 개발 속도 높이기 NDC2011
코드 생성을 사용해 개발 속도 높이기 NDC2011코드 생성을 사용해 개발 속도 높이기 NDC2011
코드 생성을 사용해 개발 속도 높이기 NDC2011Esun Kim
 

Similar to [NDC 2016] 유니티, iOS에서 LINQ 사용하기 (20)

Lecture 1: Introduction to Python and TensorFlow
Lecture 1: Introduction to Python and TensorFlowLecture 1: Introduction to Python and TensorFlow
Lecture 1: Introduction to Python and TensorFlow
 
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
 
I phone 2 release
I phone 2 releaseI phone 2 release
I phone 2 release
 
Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료
Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료
Tech-days 미니 토요세미나 - 3회 C#편 PPT 자료
 
NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서
NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서
NDC 2011, 네트워크 비동기 통신, 합의점의 길목에서
 
Hoons 닷넷 정기세미나
Hoons 닷넷 정기세미나Hoons 닷넷 정기세미나
Hoons 닷넷 정기세미나
 
Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015Going asynchronous with netty - SOSCON 2015
Going asynchronous with netty - SOSCON 2015
 
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C#  혼합 멀티플랫폼 게임 아키텍처 설계[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C#  혼합 멀티플랫폼 게임 아키텍처 설계
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계
 
불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14
 
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
 
[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...
[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...
[C++ korea] effective modern c++ study item 14 declare functions noexcept if ...
 
20201121 코드 삼분지계
20201121 코드 삼분지계20201121 코드 삼분지계
20201121 코드 삼분지계
 
C# Game Server
C# Game ServerC# Game Server
C# Game Server
 
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
NDC 2017 하재승 NEXON ZERO (넥슨 제로) 점검없이 실시간으로 코드 수정 및 게임 정보 수집하기
 
About Visual C++ 10
About  Visual C++ 10About  Visual C++ 10
About Visual C++ 10
 
Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary
 
니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트
 
강의자료 2
강의자료 2강의자료 2
강의자료 2
 
코드 생성을 사용해 개발 속도 높이기 NDC2011
코드 생성을 사용해 개발 속도 높이기 NDC2011코드 생성을 사용해 개발 속도 높이기 NDC2011
코드 생성을 사용해 개발 속도 높이기 NDC2011
 

[NDC 2016] 유니티, iOS에서 LINQ 사용하기

  • 1. 유니티 iOS에서 LINQ 사용하기 내 코드가 이렇게 간결할 리 없어 넥슨 지티 김대희
  • 2. 발표자 김대희 게임 프로그래머 4년 차 선데이토즈, 넥슨 코리아를 거쳐 현재 넥슨 지티에서 신규 모바일 게임 제작 중
  • 4. LINQ Language-Integrated Query 데이터 저장소 종류와 관계 없이 저장소에 일관성 있는 인터페이스로 질의 LINQ to Objects, LINQ to SQL, LINQ to XML ... 본 세션에서는 LINQ to Objects 관련 내용만을 다룹니다.
  • 5. LINQ int[] numbers = { 5, 10, 8, 3, 6, 12 }; Query syntax var results = from num in numbers where num % 2 == 0 orderby num select num * 2; foreach(var result in results) Console.WriteLine(result); Method syntax var results = numbers .Where(num => num % 2 == 0) .OrderBy(num => num) .Select(num => num * 2); foreach(var result in results) Console.WriteLine(result);
  • 6. LINQ 사용 예시 정말 간결할까요?
  • 7. 기획서의 요구사항 1) 퀘스트들의 제목을 출력해주세요. 2) 입장한 맵에 해당되는 퀘스트들만 보여줍니다. 3) 현재 진행 중이어야 하고요. 4) 진행 상태가 높은 퀘스트를 가장 먼저 출력합니다. 5) 진행 상태가 같은 경우 퀘스트 아이디가 낮은 순서로 출력합니다.
  • 8. 기획서의 요구사항 List<Quest> results = new List<Quest>(); foreach (Quest quest in quests) { if (quest.IsActive) { if (quest.MapIndex == currentMapIndex) results.Add(quest); } } results.Sort((x, y) => { int compareValue = y.Progress.CompareTo(x.Progress); if (compareValue == 0) return x.ID.CompareTo(y.ID); return compareValue; }); foreach (Quest quest in results) Console.WriteLine(quest.Title); Non LINQ
  • 9. 기획서의 요구사항 var results = quests .Where(quest => quest.IsActive) .Where(quest => quest.MapIndex == currentMapIndex) .OrderByDescending(quest => quest.Progress) .ThenBy(quest => quest.ID); foreach (Quest quest in results) Console.WriteLine(quest.Title); 참 쉽죠? LINQ
  • 10. LINQ 동일한 인터페이스 사용 - 모든 컬렉션 류, 그 외 다른 종류의 저장소에도 동일함. 다양하고 편리한 기능 - Max, Min, Average, OrderBy, First, FirstOrDefault, Last, LastOrDefault … 지연 실행 - 성능 이점 간결한 High Level 코드 품질 - 유지 보수 용이 컴파일 타임 에러 체크 – SQL 시 문자열 쿼리의 체크를 컴파일 타임에 가능
  • 11. LINQ LINQ는 느리다? LINQ (to Objects)는 충분히 빠르다
  • 12. LINQ Galaxy S3 100개 1,000개 10,000개 100,000개 Non LINQ 0 ms 0 ms 4 ms 42 ms LINQ 0 ms 2 ms 26 ms 250 ms iPhone 6+ 100개 1,000개 10,000개 100,000개 Non LINQ 0 ms 0 ms 3 ms 16 ms LINQ 0 ms 1 ms 10 ms 37 ms ‘기획서의 요구사항’ 성능 테스트
  • 13. LINQ 디바이스 성능은 계속 발전 - 차이가 점점 좁혀진다. 80-20 법칙 - 최적화가 필요한 곳만 코드를 풀어 쓰자 클라이언트 사이드에서 대용량의 데이터를 사용하는 곳은 많지 않다. - 100,000개의 요소를 가진 컬렉션은 거의 없다.
  • 15. LINQ on iOS List<string> strs = new List<string> { “0”, “1”, “2”, “3” }; string first = strs.FirstOrDefault (); Debug.Log(first); // “0" 문제 없음
  • 16. LINQ on iOS List<int> numbers = new List<int> { 0, 1, 2, 3 }; int first = numbers.FirstOrDefault (); Debug.Log(first.ToString()); ExecutionEngineException: Attempting to JIT compile method 'System.Linq.Enumerable/PredicateOf`1<int>:.cctor ()' while running with --aot-only. Rethrow as TypeInitializationException: An exception was thrown by the type initializer for PredicateOf`1
  • 17. LINQ on iOS LINQ 코드는 System.Core.dll에 존재하여 디버깅도 못해보고 많은 Unity 사용자들은 LINQ 사용을 포기
  • 18. Analyzation LINQ 소스가 있는 System.Core.dll를 디컴파일 앞서 문제가 있었던 FirstOrDefault 메소드 관련 부분만 발췌
  • 19. public static class Enumerable { public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source) { return First (source, PredicateOf<TSource>.Always, Fallback.Default); } private static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, Fallback fallback) { foreach (TSource source1 in source) { if (predicate(source1)) return source1; } if (fallback == Fallback.Throw) throw new InvalidOperationException(); return default(TSource); } private enum Fallback { Default, Throw, } private class PredicateOf<T> { public static readonly Func<T, bool> Always = (t => true); } } IEnumerable<int> source Func<int, bool> predicateIEnumerable<int> source PredicateOf<int>.Always 이 녀석이 문제
  • 20. public static class Enumerable { public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source) { return First (source, PredicateOf<TSource>.Always, Fallback.Default); } private class PredicateOf<T> { public static readonly Func<T, bool> Always = (t => true); } … } 예외가 발생하지 않는다. void _unusedMethod() // type hint, 해당 메소드는 어디서도 호출 되지 않습니다. { new PredicateOf<int>(); }
  • 21. C# 실행 환경 C# Source Code IL (Intermediate Language) Machine Code C# Compiler JIT Compiler RuntimeCompile time C# Source Code IL (Intermediate Language) Machine Code C# Compiler AOT Compiler Compile time JIT AOT iOS에서의 구동환경
  • 22. Mono AOT Limitations Generic 과 관련하여 특정 상황에서 Generic Type Parameter가 Value Type일 때 한계를 보임
  • 23. Generic Type Parameter List<int>, List<string>, List<float> 위 세 타입은 전부 다른 타입 각기 다른 타입이기에 전부 다른 Machine Code를 생성해야 하지만...
  • 24. Generic Code Explosion Generic Type Parameter마다 각기 다른 타입에 대해 Machine Code를 생성하게 되면 코드 양 급증 성능에 부정적인 영향
  • 26. Generic Sharing AOT의 Generic Type Parameter가 Value Type일 때만 문제가 발생하는 이유는 이와 같이 다른 메커니즘을 지니기 때문 또한 상대적으로 Reference Type에 비해 Value Type은 Generic Type Parameter 마다 코드를 생성해야 하기 때문에 AOT의 경우 코드가 누락될 가능성이 생김. 이 페이지의 내용은 발표자의 가설입니다.
  • 27. Exception ExecutionEngineException: Attempting to JIT compile method 'System.Linq.Enumerable/PredicateOf`1<int>:.cctor ()' while running with --aot-only. Rethrow as TypeInitializationException: An exception was thrown by the type initializer for PredicateOf`1 System.Linq.Enumerable/PredicateOf<int>의 Class Constructor(cctor) 메소드를 찾을 수 없어 JIT Compile를 시도하다가 난 예외
  • 28. Exception 몇 몇 복잡한 상황에서 AOT 컴파일러가 Generic 타입을 캐치하지 못한 채 실행 파일을 생성. 따라서 이전에 언급한 구체적인 타입에 대한 힌트를 주게 되면 AOT 컴파일러는 해당 타입에 대한 코드를 미리 생성 가능. void _unusedMethod() // type hint { new PredicateOf<int>(); }
  • 29. LINQ in Mono 3.x #if !FULL_AOT_RUNTIME private class PredicateOf<T> { public static readonly Func<T, bool> Always = (Func<T, bool>)(t => true); } #endif public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source) { #if !FULL_AOT_RUNTIME return First<TSource>(source, PredicateOf<TSource>.Always, Fallback.Default); #endif foreach(var element in source) return element; return default(TSource); } Mono 3.x는 해당 버그를 우회했다. 유니티는 Mono 2.x를 사용
  • 30. 그 외… 몇 몇 메소드의 경우 특정 상황에서 Lambda 또는 익명 메소드를 AOT 컴파일 하지 못한다.(Generic과 무관) 해당 Lambda 또는 익명 메소드를 멤버 메소드로 바꾸면 예외가 사라진다. public static double Average (this IEnumerable<int> source, Func<TSource, int> selector) { return source.Select(selector).Average<int, long, double> (source, (a, b) => a + b, (a, b) => (double) a / (double) b); } public static double AverageModified(this IEnumerable<int> source, Func<TSource, int> selector) { return source.Select(selector).Average<int, long, double> (source, Func1, Func2); // Lambda를 멤버 메소드로 대체 } static long Func1(long a, int b) { return a + b; } static double Func2(long a, long b) { return (double)a / (double)b; } 실제 발표 시 해당 페이지의 일부 내용이 잘못 표기 되어 수정되었습니다. 이 메소드 내부에 사용한 람다식의 코드를 생성하지 못한다. ex> Action action = () => Debug.Log(“Foo”); action();
  • 31. 그 외… 그 외에도 여러 가지 패턴의 AOT 관련 예외가 있으며 자세한 사항은 아래의 링크에서 확인. - http://neue.cc/2014/07/01_474.html
  • 32. LINQ Exception iOS 환경에서 LINQ를 사용할 수 없는 이유는 LINQ 자체의 결함이 아니라 mono AOT 컴파일러의 버그가 원인
  • 33. 그럼 어떻게 해야 하나요? 지금까지 내용은 다 잊어도 좋습니다. 지금부터 내용은 잊으면 안 됩니다.
  • 34. Third party library UniLinq - Mono 3.10.0의 LINQ 코드를 기반 - 307개의 유닛테스트 - using UniLinq; - https://github.com/RyotaMurohoshi/UniLinq
  • 35. IL2CPP Unity Technology에서 만든 AOT 기술. iOS 64bit 지원 현재 최신 버전의 IL2CPP는 안정적으로 LINQ를 지원(ver. 5.2.1f 에서 확인)
  • 36. IL2CPP vs Mono AOT C# Source Code IL (Intermediate Language) C# Compiler IL2CPP AOT Compiler Compile time C++ Source Code Machine Code C++ Compiler C# Source Code IL (Intermediate Language) Machine Code C# Compiler AOT Compiler Compile timeMono AOT IL2CPP
  • 37. LINQ with IL2CPP // Test.cs public class Test : MonoBehaviour { void Start () { List<int> intList = new List<int> () { 0, 1 }; intList.FirstOrDefault (); List<float> floatList = new List<float> { 0, 1 }; floatList.FirstOrDefault (); List<string> stringList = new List<string>{ "0", "1" }; stringList.FirstOrDefault (); List<Material> materialList = new List<Material> (); materialList.FirstOrDefault (); } }
  • 38. LINQ with IL2CPP // Bulk_Generics_3.cpp // System.Collections.Generic.List`1<System.Int32> struct List_1_t3644373756; // System.Collections.Generic.List`1<System.Object> struct List_1_t1634065389; // System.Collections.Generic.List`1<System.Single> struct List_1_t1755167990; List<string> methods List<Material> methods Shared string, Material은 Reference Type int(Int32), float(Single)은 Value Type
  • 39. LINQ with IL2CPP // GenericMethods0.cpp // TSource System.Linq.Enumerable::FirstOrDefault<System.Int32>(System.Collections.Generic.IEnumerable`1<TSource>) extern "C" int32_t Enumerable_FirstOrDefault_TisInt32_t2847414787_m1700521655_gshared (Il2CppObject * __this /* static, unused */, Il2CppObject* ___source, const MethodInfo* method) { { Il2CppObject* L_0 = ___source; Check_Source_m228347543(NULL /*static, unused*/, (Il2CppObject *)L_0, /*hidden argument*/NULL); Il2CppObject* L_1 = ___source; IL2CPP_RUNTIME_CLASS_INIT(IL2CPP_RGCTX_DATA(method->rgctx_data, 0)); Func_2_t3308141622 * L_2 = ((PredicateOf_1_t2617073743_StaticFields*)IL2CPP_RGCTX_DATA(method->rgctx_data, 0)->static_fields)->get_Always_0(); int32_t L_3 = (( int32_t (*) (Il2CppObject * /* static, unused */, Il2CppObject*, Func_2_t3308141622 *, int32_t, const MethodInfo*))IL2CPP_RGCTX_METHOD_INFO(method->rgctx_data, 1)->method)(NULL /*static, unused*/, (Il2CppObject*)L_1, (Func_2_t3308141622 *)L_2, (int32_t)0, /*hidden argument*/IL2CPP_RGCTX_METHOD_INFO(method->rgctx_data, 1)); return L_3; } }
  • 41. LINQ with IL2CPP // Enumerable.cs 원본 PredicateOf private class PredicateOf<T> { public static readonly Func<T, bool> Always = (t => true); }
  • 42. LINQ with IL2CPP // System_Core_System_Linq_Enumerable_PredicateOf_1_ge108692892.h // System.Linq.Enumerable/PredicateOf`1<System.Int32> struct PredicateOf_1_t2617073743 : public Il2CppObject { public: public: };
  • 43. LINQ with IL2CPP // System_Core_System_Linq_Enumerable_PredicateOf_1_ge108692892.h // System.Func`2<System.Int32,System.Boolean> struct Func_2_t3308141622; struct PredicateOf_1_t2617073743_StaticFields { public: // System.Func`2<T,System.Boolean> System.Linq.Enumerable/PredicateOf`1::Always Func_2_t3308141622 * ___Always_0; // System.Func`2<T,System.Boolean> System.Linq.Enumerable/PredicateOf`1::<>f__am$cache1 Func_2_t3308141622 * ___U3CU3Ef__amU24cache1_1; … public: inline Func_2_t3308141622 * get_Always_0() const { return ___Always_0; } … }
  • 44. LINQ with IL2CPP // Bulk_Generics3.cpp // System.Void System.Linq.Enumerable/PredicateOf`1<System.Int32>::.cctor() extern "C" void PredicateOf_1__cctor_m686174972_gshared (Il2CppObject * __this /* static, unused */, const MethodInfo* method) { … } // System.Boolean System.Linq.Enumerable/PredicateOf`1<System.Int32>::<Always>m__76(T) extern "C" bool PredicateOf_1_U3CAlwaysU3Em__76_m1746297546_gshared (Il2CppObject * __this /* static, unused */, int32_t ___t, const MethodInfo* method) { { return (bool)1; } } Mono AOT로 컴파일되 지 않았던 메소드가 잘 생성이 되어 있는 걸 알 수 있다.
  • 45. 결론 IL2CPP를 사용. (iOS 64bit 지원을 위해서는 반드시 사용) 만약 낮은 버전의 Unity를 사용해야 한다면 Third party library 사용 그래도 뭔가 찜찜하고 불안하면 IL2CPP에서도 소스 코드 수정이 가능한 Third party library 사용 사실 Unity에서 LINQ를 사용하지 못한다는 편견을 깨고 싶었습니다.