Jon Shemitz Complicated stuff, quickly.
description
Transcript of Jon Shemitz Complicated stuff, quickly.
Jon ShemitzComplicated stuff, quickly.
AdvancedDelegates
Advanced Delegates
Delegate syntax● Delegate Arcana 40%
Invocation lists, events, dynamic delegatesDelegates vs interfacesMiscellaneous 2.0 enhancements
● Anonymous Methods 15%
Delegates as thread primitives● Asynchronous Invoke 30%● The System Thread Pool 15%
Invocation Lists
● Delegate class manages an invocation listImplementation changed from 1.1 to 2.0Calling (invoking) a delegate is much faster in 2.0
● Each invocation list is immutableOperators like + and - return new lists
The static methods Delegate.Combine and Delegate.Remove
+= and -= work by replacement
Delegate Combining
● Value equality, not reference equalityYou do not have to -= the delegate instance you added
Can += Instance.Method now and -= Instance.Method laterYes, these are two separate delegate instances
● List length matters, on Delegate.RemoveSubtract Two from Two, and you have ZeroSubtract Four from Two, and you have Two
● These rules apply to events, too
Event Syntax
Partial understanding of events is nearly universal!● Simple, field-like events have implicit methods.
An event is never a local variable.Within its class, an event is a delegate -
Outside, an event is the implicit add and remove methods.● Complex, property-like events have no fields.
Explicit add and remove methods.Only those two methods, even within class - not storage.
Create Delegate
Delegate.CreateDelegatePass a MethodInfo, or a method name
Fewer constraints in 2.0
Calling the delegate is faster than MethodInfo.InvokeGood with dynamically generated methods
Getting dynamically loaded code by name is badSubject to collisionsInterface gets code by contract
(Code By Contract)
Standard plug-in architecture:● Contract library, used by app and plug-ins● Contains your IPlugin interface● Loading plug-in does GetExportedTypes
Finds types assignment compatible with IPlugin Creates instance, and casts to IPlugin
Delegate Enhancements in 2.0● New method group syntax
DelegateType DelegateInstance = Instance.Method;Don't have to say new DelegateType(Instance.Method)Just like Delphi ...
Instance.Method specifies an overload method groupValid delegate if one and only one overload in group
● SpeedInterface was 2½ times faster than delegate in 1.xDelegates are ca 5% faster than interfaces in 2.x
Choose on Semantics
Interface advantagesContracts & dynamically loaded code.● Interfaces are free from versioning
issues and name collisions.● You can control which methods
implement the interface.● An interface reference can give you
access to a whole personality:Other methods in interface, and other interfaces on object.
● Interfaces used to be faster than delegates. Same speed, in 2.0.
Delegate advantagesCallbacks & thread procs.● Less code to create a delegate than
to support an interface - especially when interface supported by a nested class.
● Class may offer a choice of delegate compatible methods; interface reference means the class must explicitly support the interface.
● You can create a delegate to a static or anonymous method. Interface methods are always named instance methods.
Covarianceclass Base{ public static Derived BaseFn(Base B) { return new Derived(); }}class Derived : Base {}delegate Base BaseFunction(Base B);
●In 1.x, can’t say BaseFunction F = new BaseFunction(Base.BaseFn)
A BaseFunction returns a Base instance.Base.BaseFn returns a Derived instance.
●Can, in 2.xEvery Derived instance is also a Base instance.
Contravariance class Base { public static void BaseProc(Base B) { } } class Derived : Base { public static void DerivedProc(Derived D) { }
} delegate void BaseMethod(Base B); delegate void DerivedMethod(Derived D);
●A method that takes a base type is compatible with a delegate that takes a derived type:
DerivedMethod BaseD = new DerivedMethod(Base.BaseProc);
Complicated Names
● Practical effect is that matching is looser● You'll probably only notice covariance and
contravariance when 2.0 code won't compile under 1.x, “even though it's not using generics”
● Don't put effort into telling them apart, or even remembering details of how matching is looserJust remember assignment compatibility
That's it for the basics
Any questions?
Advanced DelegatesAnonymous MethodsAsynchronous calls
Delegates are asynch primitives
When a method isn't right
Is there something wrong with named methods?Until 2.0, delegates always referred to named methods.
Usually fine - but there are three problems:● Callbacks are hard to read.
They make you jump around. They add clutter and bloat.● No tie between callback and caller.● Boilerplate - copying local variables to tiny state
objects to support callbacks &c.
Anonymous Methods● Defining a method just so that you can create a delegate to it
makes your code harder to write and harder to read.● Part of a method has been hoisted into another method.
● C# 2.0 supports anonymous methods, which let you create a delegate to a special statement block, within a method.
● The compiler does the hoisting.● You can't call an anonymous method by mistake.● The compiler does capture better than you do.
(The next screen is about capture.)
Capture● Anonymous methods can capture parameters and/or local
variables.● Captured variables are implemented as fields in a singleton
instance of a Compiler Generated Class. Captured parameters are copied in, by method prologue,
then only referred to as CGC fields.● Captured variables last as long as the delegate lasts.● Anonymous methods are named methods of the CGC.
Anonymous Method Syntax
● delegate (optional parametersparameters) {}An anonymous method never has a return type
● Valid in delegate expressions:In assignment;
DelegateType DelegateInstance = delegate(int N) {}; // note the ; after the }
As a parameter to a method; Fn(delegate {})
Event list editing.SomeEvent += delegate(object sender, EventArgs E) {};
Asynchronous Calls
● You can run any delegate in a thread Available in 1.0 Most people don't know this Syntax is weird, so people “pass” and never return You have to add two null parameters to BeginInvoke
● Functional programmingEndInvoke is like Join, except it returns a typed result.Delegates are asynch primitives:
Easiest way to pass parameters & get thread results.
Asynchronous Invoke
The best way to pass data to/from a threadFor example: read file to string
Start a read runningDo any other setupEndInvoke when really need resultA cheap, functional thread
Takes a stringReturns a string
May use ThreadPool directly if don't need result.
Runtime Methods
All delegates have runtime methods● Synchronous Invoke, in caller's thread● Asynchronous BeginInvoke, in ThreadPool thread
Returns IAsyncResult● EndInvoke takes that IAsyncResult
IAsyncResult contains a wait handleMust always call EndInvoke
EndInvoke
● BeginInvoke starts asynch call● Collect results with .EndInvoke()
Returns same type as delegateWhether void or string or whatever
Can use asynch invoke with void delegate to pass parameters -Cheaper than creating anonymous method that captures parameters.
No casting!● Less overhead than creating new Thread
Less OS work, and less user code
Control.BeginInvoke
● Two different BeginInvoke methodsBoth return IAsyncResultNever confuse the two!
● Delegate BeginInvoke runs in own threadMust call EndInvoke
● Control.BeginInvoke runs in control's threadCan omit call to EndInvoke
A Parallelizing Example//foreach (T Datum in Data)// P(Datum); // Process each Datum in the current thread
public class ThreadEach<T>{ public delegate void Processor(T Datum);
public static void Process(Processor P, IEnumerable<T> Data) { List<IAsyncResult> AsyncResults = new List<IAsyncResult>();
// Process each Datum in its own thread foreach (T Datum in Data) AsyncResults.Add(P.BeginInvoke(Datum, null, null));
// Wait for all threads to finish foreach (IAsyncResult Async in AsyncResults) P.EndInvoke(Async); }}
That was a bad example
What was wrong with that?● Not a good template
Each delegate has own parameter list● Too many threads!
Need to match thread count to processor countUse a Semaphore so only one thread per processorEach thread signs in and signs out
Those Two Nulls
● The 'extra' parameters to BeginInvokeDon't have to be null
● A delegate called after asynch delegate returnsIn same ThreadPool thread
● A parameter to the callback delegateHard to see point of this - butCan be used for fire and forget
Explicit ThreadPool is better for this
The system ThreadPool
A high level of control When you manually create a thread
Priority, IsBackground, etc
You don’t need that level of control in every app
Creating a thread is cheaper than creating a processBut it’s not free – there are setup and teardown costs
The ThreadPool reuses threads
Thread reuse
When you explicitly create a Thread:Thread executes the delegate passed to constructorThread dies when delegate returnsThread is a foreground thread, by default
A TheadPool thread:A background threadDelegate to method of object with delegate field
Executes stored delegateOn return, add the thread to a ready list A new stored delegate when wait handle signals
Cheaper and Less Code
Defers Thread destruction until process terminationMore importantly:Reusing threads reduces threads a process creates
ThreadPool takes less code, tooJust pass a delegate to a method, and it executesDon't have to Start a Thread
Explicit ThreadPool
ThreadPool.QueueUserWorkItem static method Executes a WaitCallback delegate
delegate void WaitCallback (object state)
Only one parameter, and it's untypedAnonymous methods can capture state information
(example on the next slide)
Explicit Exampleprivate static void CaptureExample()
{
string Report = @"Some very big string";
string Filename = @"\A\Drive\Near\You\Report.txt";
ThreadPool.QueueUserWorkItem(delegate {
WriteFile(Filename, Report);
} );
}
Captures Filename and Report from containing method.
Wait callbacks
The WaitCallback delegate is strangely namedIt's often executed straight-away
The ThreadPool has a different sort of wait callbackThreadPool.RegisterWaitForSingleObject
Takes a WaitOrTimerCallback delegate and a wait handle
More efficient, less reliableOne blocked thread, instead of manyMay want to compile a blocking script
Thank you
Any Questions?
Midnight Beach
ContractingConsultingTraining
Jon Shemitz
Talks fast.
Codes fast, too.