Здравствуйте, vdimas, Вы писали:
V>Хотя, подозреваю, что быстродействие вызова UnmanagedCallersOnly-метода должно быть примерно на уровне DllImport.
Ну, с практической точки зрения там почти всё — бессмысленно. Вот эти все "давайте получим анменеджед указатель на менеджед делегат, и вызовем его из менеджед кода" — нулевая практическая ценность.
Удивительно то, что вызов через делегат, ещё недавно чуть ли не на порядок проигрывавший вызову через интерфейс, теперь сравнялся — у меня делегат вышел даже быстрее.
В общем, предсказуемым образом, менеджед код быстрее всего вызывать через managed func pointer, а анменеджед — через PInvoke без переключения GC.
Самый дешёвый вызов — по менеджед указателю — на моём процессоре стоит 7ns. Вызов через делегат — 16ns, в 2.3 раза дороже. Примерно в том же классе вызов через интерфейс.
Вызов простого PInvoke, который сам быстро исполняется и не лезет в менеджед-данные, стоит 22.5ns — втрое дороже, чем менеджед вызов, но всё ещё в 2.5 раза дешевле, чем обычный PInvoke через DllImport или через GetProcAddress. (73 ns). Вызовы менеджед кода как анменеджед стоят космически дорого (1мкс), но они и не нужны. Более жизненным сценарием было бы замерить вызов менеджед кода через колбэк.
Но и там основное, для чего нужно такое измерение — это чтобы понимать, какими должны быть масштабы объёма нативной работы, чтобы взаимодействие с ней было оправданым.
То есть когда мы говорим "вот тебе десять мегов данных, позови меня, когда отправишь" — это норм. А когда мы говорим: "вот тебе массив из 100 менеджед указателей, давай ты его отсортируешь, вызывая вот этот колбек для сравнения каждого из них" — это не норм, не надо так делать.