310 likes | 428 Views
Why Be Concurrent?. CET306 Harry R. Erwin University of Sunderland. Roadmap. Why Concurrency? Test Driven Development Refactoring Threading in C#. Texts.
E N D
Why Be Concurrent? CET306 Harry R. Erwin University of Sunderland
Roadmap • Why Concurrency? • Test Driven Development • Refactoring • Threading in C#
Texts • Clay Breshears (2009) The Art of Concurrency: A Thread Monkey's Guide to Writing Parallel Applications, O'Reilly Media, Pages: 304. This is available on www.amazon.co.uk as a paperback and more cheaply as a Kindle edition. You don't need a Kindle to read a Kindle edition. • Mordechai Ben-Ari (2006) Principles of Concurrent and Distributed Programming, Addison-Wesley. Also available on www.amazon.co.uk This is available as a paperback only. Covers the theory in depthand will be used as a supplementary text.
Want to Go Faster? • I assume you want to write faster code. • You need to be prepared to write the code. • You need to know the syntax. • You need to know the libraries and methods. • You need to be prepared to think carefully and logically. • You need intuition.
Definitions • A system is concurrent if it can time-share. • A system is parallel if it can do more than one thing simultaneously. This is a subset of concurrent.
Why Concurrency? • Multi-core processors are now the state of the art—multiple CPUs running on a shared memory with shared resources. • The old pattern of Moore’s Law no longer applies 8(. To run faster, you have to share the work among multiple processors.
A Threading Methodology • Analysis—similar to specification, where you identify the code that can run concurrently. As a rule, start with working and already tuned code. Debugging concurrent code is a nightmare. You will use algorithm analysis and a profiler. • Design and implementation—do it. The book is mostly about this step. • Test for correctness. If the design is provably correct, you avoid much pain here. • Tune for performance. Use a profiler and check how well the code is running. Your threading may actually be affecting your tuning.
Testing and Tuning • If you modify your code to improve its performance, you can introduce standard bugs and threading bugs. • Standard bugs are the bugs you can often detect using test-driven design. It’s useful to have a collection of unit tests around to check for them. • Threading bugs are the really nasty ones, because they depend on thread ordering. Design defensively to avoid these bugs. If you can prove your design is correct, you don’t have to do exhaustive (and exhausting) thread testing.
Test-Driven Development and Refactoring • Test-Driven Development • Unit Testing • A Catalogue of Refactorings
Sources • Fowler, 2000, Refactoring: Improving the Design of Existing Code, Addison-Wesley. Available electronically at the library. • http://www.amazon.com/exec/obidos/tg/detail/-/0321109295/103-4060125-0311065 • http://www.amazon.com/exec/obidos/ASIN/0130648841/103-4060125-0311065 • http://www.refactoring.com/catalog/ • http://www.win.ua.ac.be/~lore/refactoringProject/index.php • Extensive discussions on the comp.object newsgroup.
Test-Driven Development • Refactoring depends on having good unit tests. This means you need to be doing test-driven development. • Test-driven development is a method of software development where tests specify interfaces of implementation and all code must have passed the tests. (Wikipedia)
How Bob Martin Describes TDD (personal communication) • Erwin: TDD as I understand it: • 1. Write a test for a bit of functionality. • 2. Show that it fails. • 3. Write the code to make the test pass. • Martin: A good summary, but there's more. • 1. We do not write production code until there is a failing test. • 2. We write the simplest possible production code to get the test to pass. • 3. We do not write more tests when we have a failing test. • 4. We do not add to a failing test.
Martin Comments Further • If you watched someone doing TDD you would see them oscillating between test code and production code once every minute or so. • During each oscillation the programmer would add a few lines to his test code, thus making it fail (or not compile) and then add just a few lines to his production code in order to make the test pass (or compile). • Each oscillation is so simple that it's not worth taking. • Each oscillation is so simple that the risk of error is close to zero. • If you walk into a room of people working this way, and chose anyone at random, a minute ago all his code would have been working.
Automated Unit Testing • Originally defined for Java (Junit). • Ported to .Net as NUnit • See http://www.nunit.org/ • Also see http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks • I strongly recommend use of such a framework.
Refactoring • Deals with code rot. Your program works but it has become ugly as it has been modified. • “Refactoring is a technique to restructure code in a disciplined way. For a long time it was a piece of programmer lore, done with varying degrees of discipline by experienced developers, but not passed on in a coherent way.” (Fowler)
Refactoring Principles • Change only the implementations • Use it to improve the design of software • Use it to make software more understandable • Use it to help find bugs • Use it to help you program faster • Use it to prepare your current program for modification.
When? • “Three strikes and you refactor.” • The third time you have to cope with something ugly, fix it. • particularly… • When you add functionality • When you need to fix a bug • When you do a code review
The Basic Rule of Refactoring • “Refactor the low hanging fruit” http://c2.com/cgi/wiki?RefactorLowHangingFruit • Low Hanging Fruit (def): “The thing that gets you most value for the least investment.” • In other words, don’t spend much time on it. There are always ways to improve any design incrementally. We will explore a few of them.
The Goal of Refactoring • To improve code without changing what it does. • This in some ways is similar to how an optimizing compiler restructures code.
Kinds of Refactorings • Composing Methods • Moving Features Between Objects • Organizing Data • Simplifying Conditionals • Making Method Calls Simpler • Generalization • Big Refactorings
Recommendations • Do some reading on Test Driven Development. • Choose and learn to use a unit testing framework. • Do more reading on refactoring in C#. The Fowler book is for Java, but the same techniques carry over to C# • Learn the features supporting refactoring in Visual Studio 2010.
Refactoring Conclusions • Kent Beck says: This is “only the beginning.” • Why? Questions we’ve left unaddressed include when to use refactoring and when to let well enough alone. • Beck’s advice: • Pick an achievable goal • Stop when you’re unsure • Backtrack if necessary • Work with a partner
Background of Parallel Algorithms • Next Week
Threading in C# • Creating and running threads • Managing threads • Synchronisation
General • To work with threads in C#, you need to import System and System.Threading. The code is: using System; using System.Threading; • Some key classes are Thread and ThreadStart.
Creating and Running Threads • In C# you use a ThreadStart delegate to create a Thread. The argument to ThreadStart is the name of a method that returns void and will be the run() method of the thread. • The Thread constructor can implicitly wrap its argument in a ThreadStart delegate. • Thread can also take a lambda expression as an argument. • Thread t = new Thread( ()=>aMethod(arguments));
Example PseudoCode Namespace whatever{ class Foo { // various variables and constructors public void Dowhatever() {etc.} // the run method static void Main(String[] args){ Foo f = new Foo(whatever); Thread t = new Thread(new ThreadStart(f.Dowhatever); t.start(); } } }
Managing Threads • This is where the various Thread methods come in. (next slide) • The ThreadPool class is available and is used to make efficient use of multiple threads. You queue work items in the ThreadPool and provide callback delegates to be executed when the work items complete. • We’ll get into this in more detail later.
Thread • Interesting members include: • Thread.Sleep(msec); —note this is class level— • Name(string); —give it a name— • Priority(ThreadPriority); —give it a priority— • Abort(); —die— • Interrupt(); —wake immediately— • Join(); —have the calling thread wait until exit— • Resume(); —unsuspend— • Start(); —start the thread— • Suspend(); —take a break—
Synchronisation • If threads share data, access must be managed to avoid conflicts. • One class used to manage this is the Monitor class. If you want to lock an Object, call Monitor.Enter(Object). When you’re done with it, remember to call Monitor.Exit(Object). This needs to be packaged in a try{} finally{} construct to avoid errors making locks permanent. • The easiest way to do this is lock(this){etc.} which hides the hassle from you.
Conclusion • The tutorial today plays around with these ideas. See you there!