Bilimsel kütüphanelerde hatalar nasıl bildirilmelidir?


11

Farklı yazılım mühendisliği disiplinlerinde, kütüphanelerin hatalarla veya diğer istisnai koşullarla nasıl başa çıkması gerektiği konusunda birçok felsefe vardır. Gördüğüm birkaç örnek:

  1. Sonuç bir işaretçi bağımsız değişkeni tarafından döndürülen bir hata kodu döndürün. PETSc bunu yapar.
  2. Hataları sentinel değerine göre döndür. Örneğin, malloc bellek ayıramadıysa NULL döndürür, sqrtnegatif bir sayı geçerseniz vb. NaN döndürür. Bu yaklaşım birçok libc işlevinde kullanılır.
  3. İstisnalar atın. Satışta kullanılır. II, Trilinos, vb.
  4. Bir varyant türü döndürün; örneğin Result, düzgün çalıştığında ve Errornasıl başarısız olabileceğini tanımlamak için bir tür kullanan bir nesne döndüren bir C ++ işlevi std::variant<Error, Result>.
  5. Onay ve kilitlenme kullanın. P4est ve igraph'ın bazı kısımlarında kullanılır.

Her yaklaşımla ilgili sorunlar:

  1. Her hatayı kontrol etmek fazladan kod getirir. Bir sonucun kaydedileceği değerlerin her zaman önce bildirilmesi gerekir ve yalnızca bir kez kullanılabilecek çok sayıda geçici değişken getirilir. Bu yaklaşım hangi hatanın meydana geldiğini açıklar, ancak neden veya derin bir çağrı yığını için nerede olduğunu belirlemek zor olabilir.
  2. Hata durumu göz ardı edilir. Bunun da ötesinde, tüm çıktı türleri aralığı makul bir sonuçsa, birçok fonksiyon anlamlı bir sentinel değerine bile sahip olamaz. # 1 ile aynı sorunların çoğu.
  3. Sadece C ++, Python, vb. İle mümkündür, C veya Fortran ile mümkün değildir. C setjmp / longjmp büyücülük veya libunwind kullanılarak taklit edilebilir .
  4. Sadece C ++, Rust, OCaml, vb. Mümkün, C veya Fortran değil. Makro büyücülük kullanarak C taklit edilebilir.
  5. Muhtemelen en bilgilendirici. Ancak, daha sonra bir Python sarıcı yazdığınız bir C kütüphanesi için bu yaklaşımı benimserseniz, bir diziye sınırların ötesinde bir dizinin geçirilmesi gibi aptalca bir hata Python yorumlayıcısının çökmesine neden olur.

İnternette hata yönetimi ile ilgili tavsiyelerin çoğu, işletim sistemleri, yerleşik geliştirme veya web uygulamaları açısından yazılmıştır. Çökmeler kabul edilemez ve güvenlik konusunda endişelenmeniz gerekir. Bilimsel uygulamalarda bu sorunlar hemen hemen aynı ölçüde yoktur.

Başka bir husus, ne tür hataların düzeltilebilir veya düzeltilemez olduğudur. Bir malloc hatası kurtarılamaz ve her durumda, OS bellek yetersiz katili sizden önce ona ulaşacaktır. Dizi boyutu için sınırların dışındaki bir dizin de kurtarılamaz. Kullanıcı olarak benim için bir kütüphanenin yapabileceği en güzel şey bilgilendirici bir hata mesajı ile çökmektir. Öte yandan, mesela, yinelemeli bir yinelemeli doğrusal çözücünün başarısızlığı, doğrudan çarpanlara ayırma çözücüsü kullanılarak giderilebilir.

Bilimsel kütüphaneler hataları nasıl raporlamalı ve ele alınmasını beklemelidir? Tabii ki bunun kütüphanenin hangi dilde uygulandığına bağlı olduğunu anlıyorum. Ama yeterince faydalı herhangi bir kütüphane için insanlar onu uyguladığı dilden başka bir dilde aramak isteyeceklerdir.

Bir yana, genel bir iddiası işleyici işlev işaretçisini genel API'nin bir parçası olarak tanımlarsa, yaklaşım # 5'in bir C kütüphanesi için önemli ölçüde geliştirilebileceğini düşünüyorum. Onaylama işleyicisi varsayılan olarak dosya / satır numarasını bildirme ve kilitlenmeyi önler. Bu kitaplık için C ++ bağlamaları, bunun yerine bir C ++ istisnası atan yeni bir onaylama işleyicisi tanımlar. Benzer şekilde, Python bağlamaları bir Python istisnası atmak için CPython API'sini kullanan bir onaylama işleyicisi tanımlar. Ama bu yaklaşımı benimseyen hiçbir örnek bilmiyorum.


Diğer bir husus performans sonuçlarıdır. Bu çeşitli yöntemler yazılımın hızını nasıl etkiler? Kodun "kontrol" kısımlarında (örn. Girdi dosyalarının işlenmesi), hesaplama açısından pahalı "motorlara" karşı farklı hata işleme kullanmalı mıyız?
LedHead

En iyi cevabın dile göre değişeceğini unutmayın.
chrylis -on strike-

Yanıtlar:


10

Referans verdiğiniz deal.II projesinde kodlanmış olan bakış açımı vereceğim.

İlk olarak, iki tür hata durumu vardır: Kurtarılabilecek hatalar ve kurtarılamayan hatalar.

  • Birincisi, örneğin, bir girdi dosyası okunamıyorsa - örneğin, böyle bir dosyadan bilgi okunuyor $HOME/.dealiiolabilir veya olmayabilir. Okuma işlevi, ikincisinin ne yapacağını anlaması için arama işlevine dönmelidir. Ayrıca şu anda bir kaynak mevcut olmayabilir, ancak bir dakika içinde tekrar bulunabilir (uzaktan takılan bir dosya sistemi).

  • İkincisi, örneğin, 20 büyüklüğünde bir vektöre 10 büyüklüğünde bir vektör eklemeye çalışıyorsanız: Olabileceğiniz gibi deneyin, bu konuda yapılabilecek hiçbir şey yoktur - kodda bir hata var ekleme yapmaya çalıştığımız nokta.

Bu iki koşul, kullandığınız programlama dilinden bağımsız olarak farklı şekilde ele alınmalıdır:

  • İkinci durumda, hiçbir başvuru olmadığından programı sonlandırın. Bunu bir istisna atarak veya arayan kişiye hiçbir şey yapılamayacağını belirten bir hata kodu döndürerek yapabilirsiniz, ancak programın sorunu ayıklamasını çok daha kolay hale getirdiğinden programı hemen iptal edebilirsiniz.

  • İlk durumda, ele alınabilecek istisnai bir durum ortaya çıkmıştır. C ve Fortran'ın bunu ifade etmenin bir yolu olmasa da, daha sonra gelen tüm makul diller, "istisnalar" sağlayarak bu "istisnai" getirilerle başa çıkmak için dil standardına yollar ekledi. Bunları kullanın - bunun için oradalar; ayrıca onları görmezden gelmeyi unutamayacak şekilde tasarlanmıştır (eğer yaparsanız, istisna sadece bir seviye daha yükselir).

Başka bir deyişle, burada savunduğum şey (ve anlaşma II. Ne yapar) bağlama bağlı olarak strateji 3 ve 5'in bir karışımıdır. 3'ün C veya Fortran gibi dillerde çalışmadığı doğrudur - bu durumda bunun, yapmak istediğiniz şeyi ifade etmeyi zorlaştıran dilleri kullanmamak için iyi bir neden olduğunu iddia edebilir.

Bazı sistemlerin, hataların kurtarılamadığı durumlarda bile çökmemesi gerektiğini not edeceğim. Bir örnek, bir dizi sorgu için bir dizi fonksiyonun tekrar tekrar çağrılmasıdır - örneğin, bir istatistiksel örnekleme şemasındaki belirli girdiler için bir olasılık fonksiyonunu değerlendirmek içindir. Belki de değerlendirici negatif değerlerle başa çıkamaz çünkü problem bu durumda bir anlam ifade etmez (örneğin, bir metal kalınlık plakasının sertliğini değerlendirmekx), ancak değerlendiricinin tekrar tekrar çağrılması gerektiğinden, yalnızca kilitlenmemeli, sadece bir istisna atmalıdır. Bu gibi durumlarda, negatif bir değerden geçmek kurtarılamaz olsa da, programı iptal etmek yerine bir istisna atmalıdır. Birkaç yıl önce bu duruşu kabul etmedim, ancak xSDK topluluk yazılım yönergeleri, programların asla çökmemesi (veya en azından çökmeden istisnaya geçmenin bir yolu olmalı) gerekliliğini kodladıktan sonra fikrimi değiştirdim. II artık Assertarama yerine istisna atma seçeneğine sahip abort().)


Ben sadece tam tersini tavsiye ederim: durum işlenemez zaman bir istisna atmak ve işlenebilir zaman bir hata kodu döndürmek. Sorun, atılan istisnalarla uğraşmanın zor olmasıdır: uygulama programcısı onları yakalamak ve işlemek için tüm olası istisna türünü bilmelidir, aksi takdirde program sadece çökecektir. Çarpışma ok ve kilitlenen noktası örneğin piton ile, ancak durumlar için-of-the-box dışarı bildirildiği için bile, ele alınamaz durumlar için hoşgeldin olabilir ele alınması, bu hoş değil (çoğunlukla) 'dir.
cdalitz

@cdalitz: Her türden nesne atabileceğiniz bir C ++ tasarım kusuru. Ancak herhangi bir makul yazılım (Trilinos hariç) sadece türetilmiş istisnalar atar std::exceptionve bunlar türetilmiş türü bilmeden referans olarak yakalanabilir.
Wolfgang Bangerth

1
Ancak orijinal soruda belirtilen nedenlerle bir hata kodu döndürme konusunda kesinlikle katılmıyorum: (i) Hata kodları çok sık göz ardı edilir ve sonuç olarak hatalar hiç ele alınmaz; (ii) birçok durumda, işlevin dönüş türünün sabit olması koşuluyla, makul bir şekilde döndürülebilecek istisnai bir değer yoktur; (iii) işlevlerin farklı dönüş türleri vardır ve her durumda bir hatayı temsil eden "istisnai" değerin ne olacağını ayrı ayrı tanımlamanız gerekir.
Wolfgang Bangerth

WB yazdı (üzgünüm, '@' hile herhangi bir nedenle çalışmıyor ve kullanıcı adı bir nedenle StackExchage tarafından kaldırıldı): "Hata kodları çok sık göz ardı edilir". Bu, istisna yakalamak için daha da fazladır: pek çok yazılım geliştiricisi, bir try / catch bloğundaki her fonksiyon çağrısını bastırma sorununu ortadan kaldırmaz. Ancak bu çoğunlukla bir zevk meselesidir: Dokümantasyon bir fonksiyonun atılıp atılmadığını ve hangi istisnaları attığını açıkça belirttiği sürece, onu halledebilirim. Ama yine de söylenebilir: belge yazma görevi çok sık göz ardı edilir ;-)
cdalitz

Ama mesele şu ki, bir istisna yakalamayı unutursanız, o zaman aşağı akış problemi yoktur: Program sadece iptal edilir. Sorunun nerede olduğunu bulmak kolay olacak. Hata kodunu kontrol etmeyi unutursanız, programınız tanımlanmamış bir iç durum nedeniyle daha sonraki bir noktada çökebilir - ancak orijinal sorunun tamamen belirsiz olduğu yerde. Bu tür hataları bulmak son derece zordur.
Wolfgang Bangerth
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.