Dlaczego nie użyć niezarządzanego bezpiecznego kodu w C #

10

W C # jest opcja wykonania niezaznaczonego kodu. Zasadniczo nie jest to zalecane, ponieważ zarządzany kod jest znacznie bezpieczniejszy i pozwala przezwyciężyć wiele problemów.

Zastanawiam się jednak, jeśli masz pewność, że Twój kod nie spowoduje błędów, a wiesz, jak obsługiwać pamięć, to dlaczego (jeśli lubisz szybki kod) postępować zgodnie z ogólną radą?

Zastanawiam się nad tym, ponieważ napisałem program do kamery wideo, który wymagał bardzo szybkiej manipulacji bitmapą. Sam stworzyłem szybkie algorytmy graficzne, które doskonale działają na mapach bitowych przy użyciu niezarządzanego kodu.

Teraz ogólnie zastanawiam się, czy jeśli jesteś pewien, że nie masz wycieków pamięci lub ryzyka awarii, dlaczego nie częściej używać niezarządzanego kodu?

PS moje tło: W pewnym sensie wkroczyłem w ten świat programowania i pracuję sam (robię to przez kilka lat), więc mam nadzieję, że to pytanie dotyczące projektowania oprogramowania nie jest takie dziwne. Naprawdę nie mam innych ludzi takich jak nauczyciel, którzy mogliby zadawać takie pytania.

użytkownik613326
źródło
8
unsafeoznacza „wiedzieć, co robisz, i porównać korzyści z ryzykiem”. Użyłem unsafekilka razy i zawsze dotyczyło to czegoś bardzo specyficznego związanego z wydajnością, które można odgrodzić własną metodą. Nie używam go jako ogólnej techniki programowania, ponieważ przez większość czasu dodatkowa korzyść z wydajności nie jest warta utraty bezpieczeństwa.
Robert Harvey,
14
Przez lata pisałem mnóstwo kodu, który czasami powodował awarię lub wycieki pamięci, i byłem prawie pewien, że nie ma wycieków pamięci ani ryzyka awarii.
whatsisname
1
Oto dobry unsafeprzykład użycia: stackoverflow.com/q/11660127/102937
Robert Harvey
3
Wydaje mi się, że twój kod bitmapowy wciąż zawiera błędy, ale po prostu ich nie wykryłeś. I nawet jeśli tak nie jest, poczekaj, aż będziesz musiał zaimplementować nowe wymagania w istniejącym kodzie.
Doc Brown,
1
Ponieważ nawet jeśli masz pewność, że kod nie spowoduje błędów, nadal będzie powodować błędy.
user253751,

Odpowiedzi:

27

Cóż, w większości przypadków jest to powiedzenie stare

  • Nie optymalizuj
  • (tylko dla ekspertów) Nie optymalizuj jeszcze

Ale tak naprawdę mogę wymyślić trzy główne powody, dla których należy unikać niebezpiecznego kodu.

  1. Błędy : krytyczna część pytania brzmi: „jeśli masz pewność, że kod nie spowoduje błędów”. Jak możesz być absolutnie pewien? Czy używałeś metody z formalnością, która gwarantowała poprawność kodu? Jedno jest pewne w programowaniu, a mianowicie, że będziesz mieć błędy. Kiedy zdejmujesz bezpieczeństwo, pozwalasz, aby nowe rodzaje błędów przenikały. Kiedy pozwalasz, aby śmieciarz zajął się twoją pamięcią, wiele problemów zniknie.

  2. Nie zawsze tak szybko, jak myślisz : Inną kwestią jest: w zależności od problemu zysk może nie być tak duży. Chociaż wydaje się, że nie mogę ich teraz znaleźć, pamiętam badanie przeprowadzone przez Google porównujące szybkość Java, Scala, Go i C ++. Po zoptymalizowaniu pod kątem ziemi C ++ był oczywiście znacznie szybszy. Ale algorytm zaprogramowany w sposób „idiomatyczny” nie był tak naprawdę szybszy. Idiomatyczny w tym sensie, że używali standardowej struktury i idiomów (kontener stl, brak rozwiniętej pętli itp.). Microsoft przeprowadził podobny eksperyment z C # i C ++. Raymond Chen, jeden z najlepszych inżynierów Microsoft, musiał napisać własną implementację std :: string, aby pokonać C #. (patrz: http://www.codinghorror.com/blog/2005/05/on-managed-code-performance-again.html) Przy znacznie mniejszym wysiłku uzyskano całkiem przyzwoitą wydajność w kodzie zarządzanym, więc często nie jest to warte kłopotu.

  3. Wielokrotnego użytku : Niebezpieczny kod może być używany tylko w środowisku pełnego zaufania. Na przykład na serwerze ASP.NET zwykle nie można użyć niebezpiecznego kodu, ponieważ wprowadzenie luki w zabezpieczeniach przez przepełnienie bufora byłoby dość łatwe. Innym przykładem może być clickonce. Lub jeśli twoja aplikacja była dostępna z udziału sieciowego. Jeśli więc planujesz używać swojego kodu w różnych scenariuszach wdrażania, niebezpieczny kod nie wchodzi w grę.

Więc w zasadzie: jest to niezadowolone, ponieważ może wprowadzać niepotrzebne błędy, może w ogóle nie przynosić korzyści i zmniejsza przydatność twojego kodu do ponownego użycia.

Ale jeśli twój scenariusz naprawdę wymaga wydajności (i masz dane, aby to udowodnić), jesteś doświadczonym programistą, który wie, jak obsługiwać pamięć, a twój kod będzie używany w kontrolowanym środowisku, więc na pewno, idź.

Laurent Bourgault-Roy
źródło
4

W pewnym sensie niezarządzany kod jest formą płatności: kupujesz szybsze wykonanie przy dodatkowym wysiłku programistycznym. Rzeczywiście, niezarządzany kod wymaga więcej czasu na opracowanie, debugowanie i utrzymanie. Prawidłowe zrobienie tego jest wyzwaniem dla większości uczestników. W pewnym sensie jest to podobne do programowania w asemblerze: na pewno możesz wycisnąć więcej mocy z procesora, jeśli piszesz w asemblerze * , ale „spędzasz” dużo więcej wysiłku, idąc tą drogą.

Czasami różnica w czasie programowania jest bardzo znacząca - dni zamiast godzin. Różnica w szybkości wykonywania nie jest jednak aż tak dramatyczna. Dlatego rozwój niezarządzanego kodu jest zarezerwowany dla sytuacji podobnych do opisanej w poście - zlokalizowanych, niezależnych implementacji algorytmów wymagających zasobów, takich jak przetwarzanie audio i wideo.

Zasadniczo odpowiedź na twoje pytanie jest podobna do odpowiedzi, dlaczego nie wszyscy jeżdżą Ferrari: to znacznie lepszy samochód, prawda? (Nie) na szczęście nie wszyscy mogą sobie na to pozwolić.


* Postępy ostatnich dziesięcioleci w technologii optymalizacji w kompilatorach tak bardzo zmniejszyły tę lukę, że nie jest to już pewny zakład.

dasblinkenlight
źródło
0

Ponieważ bycie „pewnym” co do poprawności lub jakiegokolwiek innego ograniczenia w sensie matematycznym (tj. Masz dowód) jest bardzo trudnym problemem dla języków imperatywnych. Programy często mają tak dużą liczbę stanów, że nie można ich zweryfikować nawet po sprawdzeniu każdego możliwego stanu. Tworzenie konstruktywnego dowodu nie jest czymś, co można zautomatyzować.

Powodem jest to, że ubezpieczenia, które zarządza wykonaniem, najczęściej przeważają niewielki wzrost wydajności, który można uzyskać przy użyciu niebezpiecznego kodu. Oczywiście zależy to również od konkretnego przypadku użycia.

Tamás Szelei
źródło
1
Nie sądzę, żeby miało to związek z poprawnością lub prostotą rozumowania.
Jimmy Hoffa,
Nikt nie mówi o formalnym dowodzie poprawności.
1
Jestem pewien, że twój post nie trafia w sedno, ale nie formułuję formalnego dowodu. Podobnie, mogę być pewien, że mój program jest poprawny (np. Po szeroko zakrojonych testach, debugowaniu i przedłużonym użytkowaniu w świecie rzeczywistym bez żadnych błędów), bez udowodnienia tego raz na zawsze. Ta interpretacja jest znacznie bliższa temu, co ma na myśli większość ludzi, gdy mówią „pewnie, że jest poprawna”. Metody formalne są bardzo niszowych obawy i całkowicie z uwzględnieniem dla większości deweloperów.
1
Nie widzę takiego pytania. Pytanie, które czytam, dotyczy tego, dlaczego właz ewakuacyjny ze świata zarządzanego nie jest / nie powinien być używany częściej (co sugeruje, że domyślnie zarządzany kod ma sens). W każdym razie, jeśli chcesz odpowiedzieć na to pytanie (wskazując na trudność zapewnienia poprawności), możesz to zrobić bez mówienia o absolutnym, formalnym zapewnieniu poprawności. Twoja odpowiedź na razie dotyczy wyłącznie kompletnych, dźwiękowych dowodów poprawności dla imperatywnych języków. Ale to przesada i myślę, że dowody na zarządzanym C # są równie (lub prawie tak) trudne.
1
@fish: Widzę, co mówisz. Istnieje korelacja między czymś trudnym do udowodnienia a czymś trudnym do uzasadnienia. Jeśli trudno jest udowodnić poprawność, to bardzo prawdopodobne jest, aby być pewnym, że ma rację.
Michael Shaw,
0

Krótko mówiąc, nic nie stoi na przeszkodzie, abyś wykonał całą tę pracę i zarządzał bitami programu w środowisku C ++. Ponieważ jesteś pewien, że możesz poprawnie zarządzać wszystkimi obręczami pamięci i przeciekami bez modułu wyrzucania elementów bezużytecznych, możesz to zrobić w C ++ :)

Przeciwnie, C # ma zalety zapewniające bezpieczne / zarządzane i silnie typowane środowisko programistyczne do bezpiecznego działania w środowisku .NET.

Możliwym przesunięciem wstecznym programowania niezarządzanego kodu jest dłuższy czas programowania, alokacja czasu na szczegółowe testowanie. Zyskasz oczywiście szybkość przetwarzania i większą kontrolę nad sposobem działania oprogramowania.

Tak więc opcja pracy z niezarządzanym kodem w .NET Framework od wersji 4.0 jest opcją dla przypadków skrajnych, gdy masz pewność, że może to przynieść korzyści w stosunku do nieużywania go.

Jusubow
źródło
Aha, to interesujące, że widzę, że pochodzę ze świata mikrokontrolerów i tam zwykle pisze się przyzwoite c ++, jest mało miejsca na błędy, a dobry dobry projekt oprogramowania jest najważniejszy
user613326