Přednáška: Pondělí, 15:40, S3 (Pavel Ježek)
Cvičení:
Úterý, 12:20, SW2 (Radek Zikmund)
Úterý, 14:00, SW2 (Jan Pacovský)
Úterý, 17:20, SW2 (Pavel Ježek)
Čtvrtek, 10:40, SW2 (Filip Kliber)
Stránka v SIS: NPRG038
Zakončení: Zkouška a zápočet
Table of contents
[in English] This page contains information for czech students of the Advanced C# Programming course. For english version, switch the language in the page header.
Organizace předmětu
Přednáška bude probíhat formou samostudia z video-záznamu. V době rozvržení přednášky bude probíhat živá diskuse a dotazy nad koncepty probírané na poslední (virtuální) přednášce. Podobným způsobem bude probíhat i cvičení, kde v čase rozvrženém pro cvičení bude možné pokládat libovolné dotazy ke cvičení.
Materiály z přednášek
13. Přednáška
- 13_1-WindowsFormsThreadingModel.zip
- 13_2-TasksAndLamdas-Prednaska.zip
- 13_3-TaskAsFuturesVS2012.zip
- 13_3-TaskSchedulingOptions.zip
- 13_3-TasksAndCustomWhenAll.zip
- 13_3-TasksAndWinForms.zip
- 13_3-TasksParentRelationship.zip
12. Přednáška
- 12_1-ClassConstructorsAndThreadSafety.zip
- 12_2-LockAndValueTypes.zip
- 12_3-SimpleProducerConsumer.zip
- 12_4-SimpleProducerConsumer-WeirdButCorrect.zip
11. Přednáška
10. Přednáška
- 10_1-AnonymousClasses-CastTrick.zip
- 10_2-CSharp7ValueTuples.zip
- 10_3-LinqToNothing.zip
- 10_4-LinqToNothingWithExtensionMethods.zip
- 10_5-LinqToObjectsInside.zip
- 10_6-LinqToObjectsQueryReuse.zip
- 10_Presentation.pptx
9. Přednáška
- 09_IteratorMethods.zip
- 09_IteratorMethods-GeneratedStateMachine.jpg
- 09_LazyEnumerableEvaluation.zip
- 09_ParametricIteratorMethods.zip
- 09_ParametricIteratorMethods-ParallelEnumeration.zip
- 09_ParametricIteratorMethodsWithExceptions.zip
- 09_ParametricIteratorMethodsWithExceptionsCorrect.zip
- 09_TwoArraysViaIteratorMethods.zip
- 09_TwoArraysWithoutIteratorMethods.zip
8. Přednáška
- 08_ConcurrentListModification.zip
- 08_ConsoleAppWithLibraryAliases.zip
- 08_EnumerableRandom.zip
- 08_ExplicitInternalInterfaceImplementation.zip
- 08_ForEachExplicitCast.zip
- 08_IEnumerableImplementation.zip
- 08_NamespacesAndGlobalAlias.zip
- 08_NamespacesAndNestedClasses.zip
- 08_Presentation.pptx
- 08_PrintAllWithIEnumerableT.zip
- 08_priprava.zip
7. Přednáška
- 07_AlgorithmCustomization.zip
- 07_CaptureByAccident.zip
- 07_Cpp11HelloWorld.zip
- 07_Cpp11LambdasVariableCapture.zip
- 07_LambdasAndVariableScope.zip
- 07_LambdasAndVariableScopeDecompiled.zip
- 07_MultipleLambdasAndVariableScope.zip
- 07_MultipleLambdasAndVariableScopeDecompiled.zip
6. Přednáška
- 06_Presentation.pptx
- 06_CppMemberPointerToVirtualMethod.zip
- 06_DelegateAndVirtualMethods.zip
- 06_Delegates.zip
5. Přednáška
- 05_ArraySegmentIReadOnlyListBenchmark.zip
- 05_CalcAvgVsPrintAll.zip
- 05_InterfaceOfValueTypeInvariance.zip
- 05_WhyCastingAwayIListInvarianceCompiles.zip
4. Přednáška
- 04_Presentation.pptx
- 04_ArrayCovariance.zip
- 04_GenericTypeConstrainsAndExplicitInterfaces.zip
- 04_LimitingArrayCovariance.zip
- 04_ListInvariance.zip
- 04_ReaderWriterInterfaces.zip
3. Přednáška
- 03_Presentation.pptx
- 03_CppGenericMethodAndOperatorOverloading.zip
- 03_ExtensionMethodsGettingGeneric.zip
- 03_GenericMethodsAndInheritance.zip
- 03_GenericMethodsAndOverloading-ExtendedVersionFor03.zip
- 03_GenericTypesAndStaticFields.zip
- 03_OverloadingGenericMethodsInGenericClasses.zip
2. Přednáška
- 02_Presentation.pptx
- 02_CastingToGenericMethodTypeArgument.zip
- 02_CastingToGenericMethodTypeArgument_Java.zip
- 02_CppGenericMethodsAndOverloading.zip
- 02_GenericMethods.zip
- 02_GenericMethodsAndOverloading.zip
- 02_GenericMethodsTasReturnValue-Part1.zip
- 02_MethodOverloading.zip
- 02_MethodOverloadingAndFragileBaseClass.zip
Doporučená literatura
- Mark Michaelis with Eric Lippert: Essential C# 5.0, Addison-Wesley, 2013 (lze koupit např. na Amazon UK)
- Jeffrey Richter: CLR via C# (4th Edition), Microsoft Press, December 2012 (lze koupit např. na Amazon UK)
- Jon Skeet: C# in Depth (3rd Edition), Manning Publications, September 2013 (lze koupit např. na Amazon UK)
- blog Erica Lipperta (bývalý člen C# týmu v Microsoftu): Fabulous Adventures In Coding
- C# Language Specification 5.0
Případně
- Christian Nagel, Evjen, Jay Glynn, Karli Watson, Morgan Skinner: Professional C# 4.0 and .NET 4, Wrox, John Wiley & Sons, March 2010 (lze koupit např. na Amazon UK
Náplň cvičení
12. Cvičení 2/2
- Nová vláknovací úloha (deadline 29.5.2022, 22:00, v SiSu): AsyncSemaphore
- Bonusová vláknovací úloha (deadline 3.7.2022, 22:00, v SiSu): NetChat
- Detaily o úloze shlédněte z videozáznamu (v mailu)
12. Cvičení 1/2
- Komentáře k řešení úlohy Antisocial Robots (hledání problému s atomicity violations)
- Aktualizace lokace robota (
r.Location =) nekoliduje s ostatními roboty v metoděSimulateOneStep, protože každý robot si aktualizuje svojí vlastní lokaci (takže i když se jedná o write operaci, tak pracuje s jiným místem v paměti)- Nicméně to koliduje se čtením lokace v metodě
DetermineNewLocation, protože ta zkoumá lokaci každého robota - Přístup je nutné synchronizovat nějakým zámkem
- ✖ globální zámek;
DetermineNewLocationje hlavní algoritmus, který když vzájemně vyloučíme mezi jednotlivými vlákny, tak kompletně přijdeme o veškerý paralelismus (navíc to není potřeba, nemusíme synchronizovat všechna čtení, jen odpovídající čtení a zápisy) - ✔ zámek pro každou lokaci (pro každého robota)
- ✖ globální zámek;
- Kritická sekce by měla být co nejkratší, tedy
- Zamykat pouze přiřazení v
SimulateOneStep - Stejně tak zamykat pouze čtení v
DetermineNewLocation(vyžaduje rozdělení příkazu na deklaraci a přiřazení) - Nezamykat celou iteraci cyklu! Komplikovaná/časově náročná matematika pracuje s lokální kopií lokace (isolated)
- Zamykat pouze přiřazení v
- Nicméně to koliduje se čtením lokace v metodě
- Aktualizace herní plochy při pohybu robota má stejný problém (pokud se dva roboti rozhnodnou pohnout na stejné políčko, jedná se o dvě write operace se stejným místem v paměti)
- ✔ globální zámek pro celou herní plochu; jedná se o synchronizaci pouze malé části aplikace, ale stejně by to šlo lépe v situaci kdy máme velké herní pole s menšími skupinami robotů; Příklad
- ✔ zámek pro menší část herní plochy — pro každé políčko herní plochy; to vypadá jako náročné na paměť, ale
- zámek je jen
object(0B + 16B overhead + 8B ref) a odemknutý zámek nespotřebovává žádnou další paměť; pouze zamčený ano (nicméně počet zamčených zámků nebude vyšší než počet výpočetních vláken) - Musíme vyřešit dvě data races (read + write originální lokace a read + write of nové location), tedy potřebujeme zamykat dva zámky pro originální a novou lokaci v nějakém pořadí (např.
lock(orig) lock(new)); Příklad - to vypadá jako konzistentní pořadí (první
orig, paknew), nicméně pokud si chtějí robotiAaBvyměnit políčka, pakoriglokace robotaAje ekvivalentnínewlokaci robotaB, a naopak, což vede na potenciální deadlock; to se dá vyřešit zamykáním v nějakém konzistentním pořadí (které by nemělo být moc náročné na zjištění); Příklad
- zámek je jen
- To vede na fungující (bez data race) řešení, ale měli bychom se zamyslet, jestli nezamykáme příliš moc
- Vzhledem k tomu, že je simulace nedeterministická (a záleží na plánování jednotlivých vláken), můžeme zkusit jiný přístup
- zamkneme naší původní lokaci, a novou se jen pokusíme zamknout (vyžadují přímo použití API třídy
Monitor) a pokud to nevyjde, tak se nepohneme, protože bychom se stejně nepohnuli, protože někdo jiný se na nové políčko snaží dostat (má jej zamknuté); Příklad - Metoda
TryEnterzkontroluje, jestli je zámek zamknutý a pokud ano, tak se okamžitě vrátí, nicméně takovou kontrolu tam už máme vlastní (if (_roomCells[newLoc.X, newLoc.Y] == null)) - Místo toho můžeme zamknout novou lokaci (takže jí nikdo nemůže změnit) a zkontrolovat jestli se tam můžeme pohnout, a pokud ano, tak až pak si zamknout originální lokaci (což nezpůsobí deadlock, protože nás nikdo zamknout nemůže, když tady ještě stojíme); Příklad
- zamkneme naší původní lokaci, a novou se jen pokusíme zamknout (vyžadují přímo použití API třídy
- Tím, že jsme našli sekvenci operací, které splňují definici data race, tak to ještě neznamená, že to je problém. Můžeme si nastudovat jak funguje paměťový model našeho programovacího jazyka (pravidla jak se paměť chová z pohledu runtime a předpoklady, které o paměti můžeme dělat)
- Paměťový model jazyka C# říká, že čtení a zápisy jedné proměnné referenčního typu jsou atomické. Tedy že pro referenční proměnné
aabje příkaza = batomický ve smyslu, že jiné vlákno uvidí buď původní hodnotu proměnnéa(pokud se podívá před zapsáním hodnotyb) nebo novou hodnotu proměnnéa(pokud se podívá po zapsání hodnotyb) a žádná jiná situace nemůže nastat. - Což vlastně znamená, že originální lokaci nemusíme zámkem chránit, protože se jedná o atomickou operaci
- Což vlastně znamená, že jsme nemuseli vůbec přemýšlet nad možností deadlocku, protože jsme řešení zredukovali řešení na jedno-zámkové
- Paměťový model jazyka C# říká, že čtení a zápisy jedné proměnné referenčního typu jsou atomické. Tedy že pro referenční proměnné
- Více synchronizačních primitiv
- Nová vláknovací úloha (deadline 22.5.2022, 22:00, v SiSu): AhoCorasick
- Procházení souborového systému a hledání textu v souborech
- Užitečné typy pro práci se souborovým systémem:
Directory+DirectoryInfoaFile+FileInfo - Cílem je vytvořit WinForms aplikaci, která přijímá následující argumenty:
prog.exe text path C=1 S Q- první parametr je sekvence znaků, která se má hledat
- druhá parametr je adresář, ve kterém se mají soubory hledat (rekurzivně)
- Hledání má probíhat paralelně následujícím způsobem:
- Máme množinu crawler vláken velikosti
C, které pracují nezávisle a hledají soubory (produkují jména souborů);Cje vždy 1 (tedy počet crawlerů je vždy 1) - A množinu searcher vláken velikosti
S, které prohledají konkrétní soubor a hledají v něm zadanou sekvenci znaků (konzumují jména souborů);Smůže být libovolné (třeba 4) - Kteří pracují s jednou frontou velikosti maximálně
Q(crawler-vlákna dávají soubory do fronty, searcher-vlákna si je vybírají z fronty);Qmůže být libovolné (třeba 16)
- Máme množinu crawler vláken velikosti
- V souborech je nutné binárně vyhledávat sekvenci bytů, která koresponduje zadanému textu v nějakém kódování. Je vhodné text hledat ve všech kódováních najednou (což lze efektivně algoritmem AhoCorasick)
- Hledejte
textv kódováníchEncoding.Deafult,Encoding.UTF8andEncoding.Unicode. Tyto objekty poskytují metodu.GetBytes(string), která vrátí byty, který jsou ekvivalentní danému textu v daném kódování - Implementace knihovny pro algoritmus AhoCorasick je k dispozici zde: DLL, API, Příklad použití,
- Hledejte
- Grafická aplikace musí obsahovat
ListBoxse jmény souborů, ve kterých byl nalezen zadaný text. Tento list by se měl automaticky aktualizovat tak, že se tam čerstvě nalezený soubor relativně brzo objeví (např. pomocí komponentyTimer), aLabel/StatusStrip, který obsahuje aktualizující-se statistiku v následujícím formátu:MATCH #m/ALL #a/ERROR #e/READ #r MB/ Search time: #s s, kde#mje počet souborů, ve kterých se text našel,#aje celkový počet zpracovaných souborů,#eje počet souborů, které nešlo přečíst,#rje celkýá počet přečtených MB a#sje počet uplynulých sekund od začátku hledání- Práci s UI je třeba nějak synchronizovat (dle threading modelu WinForms frameworku)
11. Cvičení
- Komentáře k řešení úlohy Merge Sort Query:
- Přímočaré řešení: Rozpůlit pole, delegovat jednu půlku do jiného vlákna a v sobě zavolat rekurzi na druhou půlku
- Předávat si počet vláken (v každé vrstvě dělit dvěma)
- Pokud množství vláken, které mám ještě k dispozici klesne na nulu, udělat jedno-vláknový
filter()asort() - Při vynoření se z rekurze, počkat na druhé vlákno (
.Join()) a udělatmerge() - Pokud se pracovní pole kopírují, nedochází ke sdílení dat a tudíž nedochází k problémům
- Možné řešení
- Prezentace o problémech s atomičností (atomicy violations) and jednoduchém zamykání
- Nová vláknovací úloha (deadline 8.5.2021, 22:00, v SiSu): Antisocial Robots
- Skeleton (stejné jako výše)
Robot.csmáLocation, což jsou souřadnice jeho pozice v herní plošeRobotSimulationBase.csmá_roomCells, což je herní plocha s referencemi na robotyRobotSimulation.csje soubor, který pracuje se dvěma důležitými funkcemi:SimulateOneStepkterá provede jeden krok simulace robota s použitím následující metodyDetermineNewLocationpro získání souřadnic políčka, kam by se měl robot pohnout
- Vaším úkolem je opravit tyto dvě metody tak, že nebudou obsahovat žádné atomicity violations; tedy zajistit, že každé použití proměnných je buď isolated, immutable nebo synchronized (pojmy z prezentace)
- Očekává se použití základních zámků ve formě
lock(obj) { ... }, tak- že to funguje (tedy nebudou nastávat atomicity violations)
- že to je efektivní (tedy řešení jedním zámkem přes celou metodu není správné)
- že se nebudou vyskytovat deadlocks
- Pozor, že vaše řešení si nemůžete otestovat. To, že vaše řešení nějak seběhne ještě neznamená, že by tomu tak bylo vždycky, vzhledem k tomu, že je paralelismus nedeterministický
- Neměňte strukturu kódu (tedy zachovejte existenci metod
SimulateOneStepaDetermineNewLocation), pouze opravte problémy související s více-vláknovým programováním - Můžete přidávat nové vlastnosti/proměnné (např. na jako zámky)
- Odevzdejte pouze
RobotSimulation.cs
10. Cvičení
- Komentáře k řešení Deque (
Deque 2.1andDeque 2.2):- Interface
IDequeje dobrý nápad- Měl by rozšiřovat rozhraní
ICollectionneboIList(protože samo o sobě to není tak užitečné)
- Měl by rozšiřovat rozhraní
- Implementace metody
IndexOf(T t)je cyklus a kontrola jestli aktuální prvek rovnát. To ale nejde udělat operátorem==(protožeTje generické), je tedy třeba použít metoduobject.Equals(object). To způsobuje boxování za situace kdeTjeValueType=> je tedy nutné zkontrolovat, jestliTimplementujeIEquattable<T>a volatIEquattable<T>.Equals(T)(tato metoda už akceptuje generický argument, tudíž nedochází k boxingu) - Zároveň je třeba dát pozor na porovnávání s
null(jakttak aktuální prvek může býtnull)- Tohle za nás zařídí
EqualityComparer<T>.Default - A celý návrh může být vylepšen tím, že Deque v konstruktoru přijímá nějaký
IEqualityComparer<T>, čímž je uživateli umožněno definovat relaci rovnosti
- Tohle za nás zařídí
- Použití verzování pro detekci modifikace kolekce během enumerace je nutné i ve variantě
yield return(neděje se to automaticky)- Vzorové řešení nesplňuje kontrakt přesně, protože k uložení aktuální verze dojde až při první volání
MoveNexta mezi to a konstruktor enumerátoru lze potenciálně ještě vložit modifikující operaci (ale principiálně nám to nic nerozbije, protože se kolekce ještě nezačala enumerovat)
- Vzorové řešení nesplňuje kontrakt přesně, protože k uložení aktuální verze dojde až při první volání
- Řešení
- Interface
- Komentáře k řešení úlohy Linq
- Postřehy k moderním CPU a jiné tipy pro řešení nové úlohy
- HyperThreading a rozdíl mezi fyzickým jádrem (core) a logickým procesorem (thread)
- PowerSavings, převážně na zařízeních s baterkou (notebooky)
- TurboBoost a automatické taktování jednotlivých jader procesoru
- Nová vláknovací úloha (deadline 1.5.2022, 22:00): Merge Sort Query
- Použití surových vláken (
System.Threading.Thread, nikolivSystem.Threading.Tasks) - Nesnažte se vymyslet komplexní řešení. Přímočaré řešení je nejlepší
- Nepoužívat
System.Linq(i přesto, že už jej znáte. V paralelním prostředí se mohou vyskytovat nějaké problémy o kterých nevíte) - Kostra řešení, případně pro .NET Core
LibraryModel/Model.csje model knihovny, která se nahraje- Obsahuje knihy (ISBN, Název, Autor, Polička)
- Polička je od
00Ado99Z - Knihovna může obsahovat vícero kopií stejné knihy (
Copy) - Kopie může být vypůjčena (
CopyState) a má unikátní ID Copy.OnLoadje popis kdo si kopii vypůjčil a kdy bude vrácena- Klient má jméno a příjmení
- Knihovna jsou seznamy knih, kopií, výpůjček a klientů
MergeSortQuery/MergeSortQuery.csobsahuje tříduMergeSortQuery- Vlastnost
ThreadCountříká maximální počet vláken, které aplikace můžou použít (včetně už bežícího vlákna) - Vlastnost
Libraryobsahuje referenci na instanci modelu - Metoda
ExecuteQueryby měla vrátit nový seznam setříděných a vyfiltrovaných kopií (více níže)
- Vlastnost
Program.csmá nastavení náhodného generátoru obsahu knihovny (default 800MB, dá se nastavit 1500MB nebo 5000MB; to vyžaduje assembly přeloženou pro procesory x64)- Také obsahuje
ReferenceTiming*.txtkteré obsahuje měření na nějakém stroji. Měření vašeho řešení by mělo vykazovat podobné vlastnosti, konkrétně- Vaše řešení pro
ThreadCount == 1by nemělo být výrazně pomalejší než referenční sériové řešení - Více vláknové řešení by mělo být viditelně rychlejší než jedno-vláknové
- Ještě více paralelní řešení (až do počtu fyzických jader vašeho procesoru) by mělo vykazovat nějaké netriviální zrychlení
- Řešení pro dvě vlákna nemůže být dvakrát rychlejší než jedno-vláknové řešení (minimálně ne proto, že finální merge nejde dělat paralelně)
- Vaše řešení pro
- Cílem je zařídit dvě věci: filtrování a třídění
- Filtr (Zamyslete se kdy filtrovat, jestli před třídění, během merge nebo po třídění)
OnLoan == trueShelfmezixxAandxxQ
- Třídění
- podle
DueDate; pak - podle
LastName; pak - podle
FirstName; pak - podle
Shelf; pak - podle
Id
- podle
- Preferujeme odevzdání pouze souboru
MergeSortQuery/MergeSortQuery.cs(ostatní soubory máte zakázáno modifikovat, kromě nastavení třídyRandomGeneratorv souboruProgram.cs) - Vaše řešení vyrábí soubory
ResultMergesort*Threads.txtaResultReference*.txt, které obsahují výsledek (tedy vyfiltrované a setříděné kopie). Vaše řešení musí mít správný výstup. Zkontrolujte si tedy Váš výstup s referenčním, třeba pomocídiffnebo nějakého checksum algoritmu (např.md5)
- Použití surových vláken (
9. Cvičení
- Povídání o Linq
- Příklady od PJ
- Nová úloha (deadline 24.4.2022, 22:00, v SiSu): Linq
- Kostra řešení
- třída
Personse jménem věkem a lidmi, které osoba považuje za své přátele (Friends, použitíFriendListInternalje zakázáno) - třída
Groupjako kolekcePerson - Ideální je připravit si metodu, která vypíše výsledek dotazu (např.
void Print(IEnumerable<Person> enum)) - Pro každý assignment v kostře doplňte jeden linq dotaz, který jej řeší
- Ideálně použitím LINQ syntaxe (tedy
from c in groupA where ..., nikolivgroupA.Where(...)) pokud je to možné - Je možné se odkazovat na předchozí dotazy (např u typu s/bez opakování)
- Není třeba přidávat další metody (kromě lambda výrazů v dotazech) nebo typy (kromě anonymních tříd v
select) - Zamyslete se nad efektivitou jednotlivých dotazů (tedy snažte se kolekce enumerovat co nejméně)
- Toto se dá ověřit porovnáním ladících informací z ukázkového výstupu (pokud Vás program produkuje příliš ladících výpisů, pak je to špatně)
- Pokud zadání neříká nic o pořadí prvků, pak na něm nezáleží (ale musí být výstup stejný ve smyslu stejných lidí)
- Očekávaný výstup: Bez ladění, s D1, s D2 (váš výstup se nemusí přesně shodovat s výstupem ve variantě D1/D2)
8. Cvičení
- Jak spojit dva repositáře do jednoho se zachováním kompletní historie?
- Pomocí remote repositáře a
git mergeremote branche - A možná přesun souborů pro lepší organizaci souborů na disku, což umí git rozpoznat jako přesun (a ne jako smazání + přidání)
- Pomocí remote repositáře a
- Další featury v gitu:
git stashagit cherry-pick: Příklad - Hinty k úloze
Deque: - Implementace
IEnumeratorby měla umět detekovat modifikaci kolekce v průběhu její enumerace, ale jak?- Pomocí verzování kolekce
int version = 0- Každá modifikující operace (pouze modifikující) udělá
version++ - Implementace
IEnumeratorsi zapamatujeversionse kterou byla vytvořena - Každá metoda/vlastnost
IEnumeratorzkontroluje jestli uloženáversion == collection.versiona pokud ne, takthrow InvalidOperationException - Podobně i pro
yield return(neděje se to samo automaticky, vždyť za iterátorovou metodou ani nemusí být žádná kolekce)
- Použití
ICollection.Addpro inicializaci kolekcí použitím syntaxenew Collection<int> { 1, 2, 3 }; - Introducing
IDequemight be a good idea - Implementace
ICollection.Addexplicitně pro schování z veřejného API třídy, kdyžIDequenabízí výstižnější (méně zmatečné) rozhraní- Což ale bohužel rozbije inicializaci syntaxí
{ 1, 2, 3 }
- Což ale bohužel rozbije inicializaci syntaxí
7. Cvičení
- Komentáře k pátému úkolu (serializační framework):
- Rozdělení na delegáty, kteří tahají hodnoty z modelu; a skutečnou serializaci těchto hodnot do nějakého formátu
- ✖ Serializace přímo v delegátech
- Pokud bychom chtěli podporovat jiný formát (např. JSON), tak si musí uživatelé přepsat konfiguraci modelu
- ✔ Možné řešení
- Použití operátoru `nameof`
- Problém je, že změna jména vlastnosti znamená, že se změní jméno tagu v XML, což způsobí nekonzistenci s jinými XML, které jsme si v minulosti zaserializovali
- Řešení, které rozděluje koncept serializace a formátu implementací visitor patternu (pokročilé řešení, ale velmi hezké)
- Rozdíl mezi
git add(z working directory do staging area) agit commit(ze staging area do repositáře) - Povídání o
git brancha rozdílu protigit tag - Generování implementace interface pomocí visual studia
- Nový úkol (deadline 17.4.2021 (dva týdny), 22:00, v SiSu, a ReCodExu): Deque 2.1
- Stejné jako bonusová úloha ze zimního semestru
- Implementace kolekce
Deque(amortizovaně konstantní složitost přidávání a odebírání prvků z obou konců) Deque<T>musí implementovatIList<T>(a tedy takéICollection<T>aIEnumerable<T>)- Implementace
ReverseView, což je jiný pohled na stejná data (nikoliv kopie) — přidání na začátek reverzního pohledu přidá na konec originální deque; enumerace reverzního pohledu enumeruje prvky v opačném pořadí; … - Bez použití
yield return - Další informací, včetně očekávané implementace, jsou v ReCodExu
- Své řešení otestujte vůči ReCodExu (ve skupině Pokročilé programování v jazyce C#)
- Odladěné řešení (které funguje na 100% testů) nahrajte do SISu, jako GIT repositář
- Nový úkol (deadline 17.4.2021 (dva týdny), 22:00, v SiSu, a ReCodExu): Deque 2.2
- Stejné, vizte výše, akorát s použitím konceptu
yield return - Odladěné řešení (které funguje na 100% testů) nahrajte do SISu, jako GIT repositář s další branch
- Stejné, vizte výše, akorát s použitím konceptu
6. Cvičení
- Praktické příklady k delegátům a anonymním funkcím (lambdy)
- Standardní C# delegáti
Action,FuncandPredicate - typ
Pointa algoritmus, který je parametrizovaný funkcí, která počítá vzdálenost v různých metrikách: Příklad - Generická metoda
Map, která transformujeIEnumerable<I>naIEnumerable<O>pomocí dodané funkce, která zajistí převod zInaO: Příklad- Odvození typů (type inference) není v tomto kontextu vůbec jednoduché, ale funguje, protože překladač umí odvodit typové argumenty funkce map
Mapz generického delegátu, který je do metody předán (který může být závislý zase na jiném argumentu)
- Odvození typů (type inference) není v tomto kontextu vůbec jednoduché, ale funguje, protože překladač umí odvodit typové argumenty funkce map
- Standardní C# delegáti
- Benchmark měřící rychlost odebírání více prvků z
Listu pomocí metodRemove(T item),RemoveAt(int index)aRemoveAll(Predicate test): Příklad- Pokud odstraňujeme více prkvů,
RemoveiRemoveAtjsou O(n2), kdežtoRemoveAllje jenO(n), protože ví, jakListfunguje a může odebrání prvků udělat v jednom průchodu - Nicméně při odebírání pouze jednoho prvku je metoda
RemoveAllnejhorší, protože volání metody skrz delegáta není zadarmo (a zabraňuje to některým optimalizacím, jako je method inlining; delegát nemůže být inlinován, když metoda na kterou ukazuje není známa při běhu) - Benchmarky jsou pouze kód a ten může obsahovat chyby, což způsobí, že výsledky benchmarku nedávají smysl (a není možné tyto výsledky použít pro dělaní jakýchkoliv relevantních závěrů)
- Pokud odstraňujeme více prkvů,
- Nová úloha (deadline 3.4.2022, 22:00, v SiSu): Serializační framework
- Kostra
- Očekávaný výstup
- Bez použití
System.Reflection - Cílem úkolu je vyrobit obecný serializační framework; a konfiguraci tohoto frameworku pro náš specifický model
5. Cvičení
- Komentáře k řešení čtvrtého úkolu (
Fixedpoint): - Podporujeme právě 32 bitů přesnosti což vede na použití typu
intjako backing type- nedává smysl rozdělení na 2x
shortnebo 4xbyte, když potenciálně mohu mítQ4_28 - použití typu
longmůže dávat smysl z pohledu větší přesnosti u násobení/dělení, ale znaménkové rozšíření zintnalongje triviální pro processor, kdežto použití přímolongmůže mít velký (paměťový) overhead (x2)
- nedává smysl rozdělení na 2x
- Rozhodnutí mezi:
- ✖
class; paměťový overhead (reference,Type, sync block) - ✔
struct; hodnotová sémantika na kterou jsme zvyklý u ostatních číselných typů
- ✖
- Kde si uložit informaci o přesnosti:
- ✖ Ve
Fixed<Q>jako instanční položku; overhead, přesnost je spojená s typem, není nutné ji mít uloženou v každé instanci zvlášť - ✔ Ve
Fixed<Q>jako statickou položku; lepší, ale inicializace závisí naQ; Příklad - ✔ V
Q(typový argument)
- ✖ Ve
- Jak zařídit dva stejné konstruktory
Fixed(int integerValue)aFixed(int internalRepresentation): - Jak vytáhnout informaci o přesnosti z
Q - Příklady hezkých scénářů na unit testování:
- Na příště není žádný domácí úkol
4. Cvičení
- Komentáře k řešení třetího úkolu:
- Factories v NezarkaGame:
- Možné řešení
- Obsahuje GIT repo s (vybranou) branch
modelstore-genericfactories
- ImmutablePeople
- Factories v NezarkaGame:
- Sémantické rozdělení C# tříd do tří kategorií: entity, kolekce (entit) a ostatní
- Kolekce mají typicky nějaké požadavky na entity
- Z
objectu metodyEquals,ToStringaGetHashCode - Interface
IEquattable<T>aIEqualityComparer<T>, a implementaceEqualityComparer<T>.Default
- Z
- Zopakování třídních konstruktorů (statická inicializace) ze zimy
- Použití
A<T>nevolá třídní konstruktor odT(pakliže neníTexplicitně použito) - Explicitní vynucení volání
.cctorprostřednictvím metodySystem.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor - Příklad
- Použití
- Představení featury Code Coverage ve Visual Studiu, která umí spočítat kolik procent kódu je pokryto unit testy
- 100% code coverage neznamená program bez chyb
- Ale < 100% code coverage znamená, že program není kompletně otestovaný
- Prezentace nástroje
BenchmarkDotNet(z NuGet balíček), který je možné použít pro vytváření robustních, statisticky lepších benchmarků, než se dá s pomocí třídySystem.Diagnostics.Stopwatch- Automaticky volá benchmark metodu vícekrát, aby došlo k nějakému zahřátí, aby se metoda stihla JIT přeložit, aby se halda dostala do nějakého běžného stavu, …
- Projekt musí být přeložen v režimu
Releasepro zajištění přesnějších výsledků - Lze nakonfigurovat aby benchmark sledoval paměťové alokace, branch mis-predikce, cache missy a další CPU čítače
- Detekuje a filtruje outliers, zobrazuje statistická data (mean, error, std dev)
- Příklad benchmark testujícího rozdíl mezi typem
doublezabaleném vclassnebostruct
- Nový DU (deadline 20.3.2022, 22:00, vložit do SiS, přečtěte si přepis mailu níže, kde se vysvětluje jak má odevzdané řešení vypadat!)
3. Cvičení
- Komentáře k prvním dvěma úlohám
- Fyzika:
Second,Meter,MeterPerSecondjakostruct, protože nechceme referenční sémentiku (jedná se o hodnoty)- Benchmark testující rozdíl mezi typem
doublezabaleném vclassnebostruct(používá knihovnu BenchmarkDotNet); Příklad
- Benchmark testující rozdíl mezi typem
- Implicitní konverze mezi jednotkami různých typů, případně pro
int/doublejsou nebezpečné (chceme zachovat silnou typovost) LimitedPositionUpdaterjen jako seskupení rychlosti a lower/upper bound (zobrazovaná část hry), protože znovu referenční sémantika nám nic nepřidá- A dovolí nám to implementovat
UpdatePosisitonjak pro vertikální tak pro horizontální pohyb
- A dovolí nám to implementovat
- Spojení naší hry a zákazníků nežárky
- Vytažení modelu do samostatného projektu, protože hra nechce vědět nic o nějakém web serveru
- Vložení instance
CustomerdoListBox:- ✖ Přidání
ToStringdoModel.Customer; Pokud bychom potřebovali vypisovat zákazníky v jiném list-boxu (v jiném projektu) jiným způsobem, tak to nebude fungovat - ✖ Přidání extension metody do
JumpingPlatformGameprojektu; Nefunguje, protožeListBoxsi vybírá metoduToStringza překladu WinForms (a to si vybereobject.ToString) - ✔ Přidání nové třídy, která dědí od
Model.Customers vlastní implementací metodyToString; problém je v tom, že model vyrábí přímoModel.Customera ne naše nové typy, tudíž je třeba model parametrizovat nějakými factories - ✔ Přidání wrapper třídy, která si pamatuje referenci na
Model.Customers vlastní implementací metodyToString; méně práce s programováním
- ✖ Přidání
- Převedení
Model.CustomernaMovableEntitypomocí nové třídy (CustomerMovableEntity), která dědí odMovableEntitya pamatuje si referenci na instanci třídyModel.Customer
- Možné řešení (obsahuje také GIT větev
modelstore-factories) - Připomenutí vytváření unit testovacího projektu
- Nový nástroj pro programátory: MarkDown
- Původně jméno nástroje pro konverzi značkovaného textu do
.html(Dnes samostatný formát) - Zdroják více čitelný než HTML
- Není standardizován. Existuje mnoho příchutí (flavours), které se chovají jinak u pokročilejších features (např. tabulky)
- Původně jméno nástroje pro konverzi značkovaného textu do
- Immutable typy a fluent/
Withsyntax - Problémy se syntaxí
Withv případě dědičnosticlass A { public A With() }vracíA.class B : A { public void f() }nedovoluje volat(new B()).With().f()protožefnení ve tříděA(resp. protožeB.With()vrátíA)- Řešení pomocí generické třídy, která má omezení na
Tdědící od právě této třídy specializovanou na sebe sama - Příklad
- Domácí úkol (deadline 13.3.2022 22:00, vložit do SISu, jako ZIP archív, obsahující dva GIT repositáře, bez dočasných/binárních souborů (clean))
- Rozšíření DU2 (
NezarkaJumpingPlatformGame) pro co nejmenší duplikaci kódu při používání factories (s využitím generiky)- Ideálně rozšířit své řešení, v horším případě použít prezentované řešení
- Odevzdat jako *novou branch v existujícím GIT repositáři
- Nový DU,
ImmutablePeople, Kostra řešení- Přidat nový soubor s implementací požadovaných tříd tak, aby se
Program.cspřeložil a vypsal stejný výstup jako je v souboruImmutablePeople.txt - Jednotlivé instance musí být immutable, modifikace probíhá pomocí metod
With(fluent syntax) - Bez použití C#9.0
record - Odevzdat jako GIT repositář obsahující
- Implementaci
ImmutablePeople - Unit testy
- Dokumentaci ve formátu MarkDown (jak se třídy používají, na jaké problémy jste narazili a jak jste je vyřešili, ToDo list, …)
- Implementaci
- Přidat nový soubor s implementací požadovaných tříd tak, aby se
2. Cvičení
- Pojmenovávání argumentů funkcí
- Pokud máme funkci
m(int a, int b), pak jsou její voláním(5, 6),m(a: 5, b: 6)am(b: 6, a: 5)ekvivalentní (a vyřeší je překladač; rozdíl není v CIL kódu vidět) - Používat jako dokumentaci, v případech kdy to pomůže s porozuměním kódu
- Pokud máme funkci
- Volitelné argumenty
- Pokud máme funkci
m(int a, int b = 6), pak jsou její voláním(1)am(1, 6)ekvivalentní (a vyřeší je překladač; rozdíl není v CIL kódu vidět) - Jiná situace je mít dvě funkce
m(int a, int b) {}am(int a) { m(a, 6) }(což jsou v přeložené assembly skutečně dvě funkce)
- Pokud máme funkci
- Příklad
- Výroba solution s vícero projekty s hezkou adresářovou strukturou
- Set as startup project
- Copy to output folder
- Použití GITu z VisualStudia
- Jednoduchá WinForms aplikace
- Použití GITu na vyčištění pracovního adresáře od dočasných souborů
- Výsledná práce
- Domácí úkol (deadline 6.3.2021, 22:00, vložit do SISu, jako ZIP archív, bez dočasných/přeložených souborů (clean), jako GIT repositář)
- Rozšíření DU1 (
JumpingPlatformGame) o možnost přidávání uživatelů z internetového obchodu Nežárka do hry jakoMovableEntity. - Řešení Nežárky (použijte toto řešení, pro konzistenci)
- Přidání
ListBox, který obsahuje zákazníky, a tlačítko, které přidá entitu s barvou podle toho kolik let je zákazník registrován v obchodě:< 1: Color.Black== 1: Color.DarkRed== 2: Color.Red== 3: Color.IndianRed> 3: Color.OrangeRed?: Color.Gold(?– od začátku obchodu)
- Rozšíření DU1 (
1. Cvičení
- Úvodní cvičení, požadavky na splnění předmětu, Slides. Informace o požadavcích na splnění předmětu jsou k dispozici taky na této stránce
- Uživatelsky definované konverzní operátory
- Pravidla pro řetězení implicitních konverzí.
- Jednoduchý příklad jak se může typ
Fractionkonvertovat z/do typuint - Příklad na nejednoznačné implicitní/explicitní konverze
- Příklad jak se implicitní konverze řetězí a jak se operátor
isrozhoduje pouze podle stromu dědičnosti
- Další uživatelsky definované operátory
- Aritmetické:
+,-(unary and binary),*,/,%,++,-- - Relační:
==,!=,<=,>=,<,> - Bitové:
&,|,^,~,>>,<< - Unární:
!,true,false - Pokud je přetížený operátor
==(nebo<,<=,true) pak musí být také přetížen operátor!=(nebo>=,>,false)! - Jednoduchý příklad sčítání typů
Fraction
- Aritmetické:
- Domácí úkol (deadline: 27.2.2022 22:00)
- Kostra
- Zařídit, aby se přeložil projekt
GamePhysicsa vypsal očekávaný výstup, bez zásahu do funkceMain(API zákazníka) - Zařídit, aby se přeložil projekt
JumpingPlatformGametak, aby měl očekávané chování, bez zásahu do souboruMainForm.cs(API zákazníka) - Projekt
JumpingPlatformGamezávisí na projektuGamePhysics. Stačí tedy upravovat souboryGamePhysics/Program.csaJumpingPlatformGame/Entities.cs
Informace o zkoušce
Zkouška probíhá primárně písemnou formou, a v každé zkouškové písemce je kolem 6 až 8 otázek (některé obsahují podotázky). U každé otázky, případně podotázky, je dole uvedeno, jaký maximální počet bodů (=N) lze za správně odpovězenou otázku/podotázku získat: N bodů získáte v případě, že je odpověď na otázku správně; 0,5 * N bodu získáte, pokud odpověď není zcela kompletní, ale jinak je správná (tj. nějaká malá část odpovědi chybí nebo je nepřesná); v ostatních případech získáte 0 bodů (tj. pokud v odpovědi chybí větší část, nebo je odpověď na otázku plně nebo i jen z části nesprávná).
Celkem lze z každé písemky získat maximálně 10 bodů. Mapování získaných bodů na výslednou známku je následující:
| Body z písemky | Výsledná známka |
|---|---|
| 10 – 8,5 | 1 |
| 8 – 6,5 | 2 |
| 6 – 5 | 3 |
| 4.5 – 0 | 4 |
Každá zkoušková písemka trvá 150 minut, tj. ideálně 20 minut na každou otázku + 30 minut bezpečnostní rezerva. Po písemné části následuje ústní část, kde zkoušející se studentem prochází jeho písemku, a případně nepřesností/nejasností u některých odpovědí se ptá na doplňující otázky — na základě toho je určeno finální bodové hodnocení každé otázky. Základem hodnocení je ale vždy písemná část, tedy u otázky bez odpovědi nebo se špatnou odpovědí nelze ani po ústní části získat více než 0 bodů.
Níže budou pro ilustraci uvedena zadání vybraných písemek z již proběhlých termínů:
Doplňkové informace o zkoušce
Kromě informací uvedených ve slidech z první přednášky navíc pro zkoušky z NPRG035, NPRG038, a NPRG057 platí následující 2 body:
- Pokud někdo bude zapsán na nějakém z termínů zkoušky a na termín se nedostaví, bude mu tento termín v SISu označen jako propadlý (tj. student přijde o jeden pokus). Cílem tohoto opatření je optimalizace vytíženosti jednotlivých termínů, aby všichni studenti měli možnost přijít až na 3 termíny zkoušky.
- Pokud někdo na zkoušce získá známku 2 nebo 3 a bude si chtít svůj výsledek zlepšit, může explicitně na místě během vyhodnocení zkouškové písemky požádat zkoušejícího o nezapsání známky. Zkušební termín mu pak bude v SISu označen jako propadlý. Takový student může pak později
- požádat o dodatečné zapsání získané známky, nebo
- přijít na jiný termín zkoušky (jakýmkoliv výsledkem této “opravné” zkoušky se ovšem anuluje předchozí získaná známka).
Modelový příklad 1:
Student X získá na 1. termínu známku 2 a odmítne ji. Na 2. termínu získá známku 3 a odmítne ji. Na 3. termínu získá známku 1.
Aktuální stav studenta X: 1. termín = propadlý, 2. termín = propadlý, 3. termín = 1, tj. student X zkoušku splnil s hodnocením 1.
Modelový příklad 2:
Student Y získá na 1. termínu známku 3 a odmítne ji. Na 2. termínu získá známku 4.
Aktuální stav studenta Y: 1. termín = propadlý, 2. termín = 4, tj. pokud chce zkoušku splnit, musí student Y přijít na 3. termín. Pokud na 3. termínu opět získá známku 4, tak zkoušku nesplnil.
Modelový příklad 3:
Student Z se nedostaví na 1. termín, na 2. termínu získá známku 3 a odmítne ji, na 3. termínu získá známku 4.
Aktuální stav studenta Z: 1. termín = propadlý, 2. termín = propadlý, 3. termín = 4, tj. student Z zkoušku nesplnil.
Informace o zápočtu
Pro získání zápočtu je nutné dvě podmínky:
1. Domácí úkoly
Během semestru bude zadáno několik (10-12) domácích úkolů. Náročnost těchto úkolů se může různit. Za správné vypracování úkolu dostane student značku OK. Pokud se v řešení vyskytnou nějaké problémy (např. chybějící implementace nějaké malé části úkolu), dostane student značku OK-. Naopak, pokud bude řešení velmi kvalitní nebo jinak nadstandardní, dostane student značku OK+. Kladné značky umí odmazávat mínuska u negativních značek. Pro splnění této podmínky je nutné získat alespoň 5 značek OK, z nichž alespoň 2 jsou na téma více-vláknového programování; nebo alespoň 1 na více-vláknové programování a alespoň 1 na dobrovolné pokročilé (extended track) koncepty. Domácí úkoly se hodnotí individuálně. Pokud si nejste celkovým hodnocením jistí (např. máte nemálo značek OK-), zeptejte se svého cvičícího.
Každá další značka OK nad 5 přidává +0.25 bodů ke zkoušce
Domácí úkoly nemají formální specifikaci. Je na zodpovědnosti studenta správně úkolu porozumět ptaním se otázek během cvičení. Domácí úkoly se odevzdávají prostřednictvím modulu Studijní mezivýsledky v SISu. Je nutné nahrávat celá řešení jako archív ZIP (samotné .cs soubory nemusí v některých případech stačit, např. pokud zadání vyžaduje připravení NuGetích balíčků). Na rozdíl od systému ReCodEx nebude studentům k dispozici okamžitý feedback k nahranému řešení, nýbrž bude třeba vyčkat na ohodnocení cvičícím.
Upozornění: Domácí úkoly jsou samostatnou prací, jejímž cílem je zhodnotit schopnost studenta samostatně vypracovat složitější program v jazyce C#. Pokud bude zjištěno, že některý student odevzdal cizí řešení (např. několik studentů odevzdalo různé instance stejného řešení některého domácího úkolu, apod.), bude to považováno za pokus o podvod. Všichni takoví studenti nesplní předmět NPRG038 v tomto akademickém roce a přicházejí o možnost uznání splněných povinností v roce příštím; případně bude disciplinární komisi UK MFF doporučeno jejich vyloučení ze studia!
2. Zápočtový program
Termíny:
- Specifikace: 15. 7. 2022
- Předvedení finální plně funkční verze (včetně uživatelské a programátorské dokumentace):
-
- deadline: 12. 8. 2022
-
- deadline: 9. 9. 2022
-
Jeden zápočtový program může být použit pro splnění povinností z vícero předmětů o C#, pokud je program dostatečně rozsáhlý.
- Požadavky pro NPRG035 + NPRG038:
- Předvedeno do 1. deadline: minimálně 45 kB zdrojového kódu v jazyce C#
- Předvedeno do 2. deadline: minimálně 60 kB zdrojového kódu v jazyce C#
- Předvedeno po 2. deadline: minimálně 90 kB zdrojového kódu v jazyce C#
Zdrojové kódy musí být ručně psané (nevygenerované) a rozumné, včetně rozumných komentářů.
Zápočtový program vyžaduje rozumné a netriviální použití technologií probíraných na přednáškách a cvičeních (jako např. více-vláknové programování, síťování, LINQ, Reflection, …).
Osobní předvedení je součástí odevzdání. Na předvádění si připravte několik slides shrnujících hlavní funkce programu, hlavní řešené problémy a nástin architektury.
Uznávání povinností z minulých let
Pokud jste tento předmět měli zapsaný loňský akademický rok a splnili jste pouze některé z povinností potřebných pro udělení zápočtu, může vám je po explicitním požádání (např. při předvádění zápočtového programu) uznat váš letošní cvičící (lze uznat splněnou docházku, domácí úkoly, zápočtový test, odevzdaný a schválený zápočtový program). Téma zápočtového programu (pokud ho ještě nemáte dokončený) nemusí být novým cvičícím uznáno. Pokud jste v loňském roce úspěšně složili zkoušku, ale nepodařilo se vám získat zápočet, opět po explicitním požádání vám může zkoušku uznat Pavel Ježek. Toto je iniciativa vyučujících tohoto předmětu a nelze ji požadovat po studijním oddělení!



























