17. Thread
• Simple API for dealing with thread
• 1:1 map to OS thread
• Foreground & background
• A lot of control == a lot of work
18. class Program
{
static void Main(string[] args)
{
Thread thread1 = new Thread(ThreadWork.DoWork);
thread1.Start();
}
}
public class ThreadWork
{
public static void DoWork()
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Working thread...");
Thread.Sleep(100);
}
}
}
20. ThreadPool
• Linked list of work items
• Reuse created threads
• Minimalize responsibility of thread
management
21. class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(ThreadWork.DoWorkInThreadPool);
}
}
public class ThreadWork
{
public static void DoWorkInThreadPool(object stateInfo)
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Hello from threadpool...");
Thread.Sleep(100);
}
}
}
22. What’s wrong?
• Thread is expensive to create
• Uncontroller threads creation
can cause consuming memory
• Working with ThreadPool is still
very complex
23. Asynchronous Programming Model APM
• Introduced with .NET 1.1
• Simplifies working with ThreadPool
• Pair of methods and call object
24. static void Main(string[] args)
{
AddictionDelegate add = AddOperation;
IAsyncResult result =
add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData");
int operationResult = add.EndInvoke(result);
}
static int AddOperation(int a, int b)
{
return a + b;
}
static void AddOperationComplete(IAsyncResult ar)
{
Console.WriteLine($"Write {ar.AsyncState}");
Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}");
}
25. static void Main(string[] args)
{
AddictionDelegate add = AddOperation;
IAsyncResult result =
add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData");
int operationResult = add.EndInvoke(result);
}
static int AddOperation(int a, int b)
{
return a + b;
}
static void AddOperationComplete(IAsyncResult ar)
{
Console.WriteLine($"Write {ar.AsyncState}");
Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}");
}
26. static void Main(string[] args)
{
AddictionDelegate add = AddOperation;
IAsyncResult result =
add.BeginInvoke(10, 5, new AsyncCallback(AddOperationComplete), "someData");
int operationResult = add.EndInvoke(result);
}
static int AddOperation(int a, int b)
{
return a + b;
}
static void AddOperationComplete(IAsyncResult ar)
{
Console.WriteLine($"Write {ar.AsyncState}");
Console.WriteLine($"ThreadId: { Thread.CurrentThread.ManagedThreadId}");
}
27. What’s wrong?
• APM make async code very
different from sync code
• Need to run End___ method to
clean up allocated resources
• Problems with GUI apps
• .NET Core?
33. public void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var result = SomeAsyncMethod().Result;
resultTB.Text = result;
}
public async Task<string> SomeAsyncMethod()
{
var result = await FetchDataAsync();
return result;
}
34. public void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var result = SomeAsyncMethod().Result;
resultTB.Text = result;
}
public async Task<string> SomeAsyncMethod()
{
var result = await FetchDataAsync();
return result;
}
35. public void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var result = SomeAsyncMethod().Result;
resultTB.Text = result;
}
public async Task<string> SomeAsyncMethod()
{
var result = await FetchDataAsync().ConfigureAwait(false);
return result;
}
36. Event-based Aysynchronous Pattern
• Each operation has
• method to start async work
• event that fires when operation is completed
• Improve error handling
• Resolve UI interaction problems
57. Task Parallel Library
• Set of software APIs in the System.Threading.Tasks
• Task represents an asynchronous unit of work
• Easier to use for developers
58. Compute-based task
• Abstraction for OS thread
• Two possibilities
• Create new thread
• Schedule work on reusable ThreadPool
• Task.Run
• TaskFactory.StartNew
59. static void Main(string[] args)
{
Task t = new Task(Speak);
t.Start();
Console.WriteLine("Waiting for completion");
t.Wait();
Console.ReadKey();
}
private static void Speak()
{
Console.WriteLine("Hello world");
}
76. [CompilerGenerated]
[StructLayout(LayoutKind.Auto)]
private struct <TestAsync>d__1 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<int> <>t__builder;
private int <firstResult>5__2;
private int <secondResult>5__3;
private TaskAwaiter<int> <>u__1;
void IAsyncStateMachine.MoveNext()
{
int num = this.<>1__state;
int result2;
80. Summary
• What lies underneath
• Better understanding of concepts
• 95% cases don’t apply
• What about these 5%
81. Summary
• What lies underneath
• Better understanding of concepts
• 95% cases don’t apply
• What about these 5%
• Avoid Wait() and
GetAwaiter().GetResult()
84. Thanks for your attention
@mtyborowski09 @tbr09mtyborowski09@gmail.com
Editor's Notes
Share access to processing cores but dont share memory
13 February 2002 – release of .NET 1.0
WinForms – BeginInvoke in Controll class
WPF, Silverlight – dispatchers
Task.Run
TaskFactory.StartNew – we can specify scheduler
ThreadPool
Kompilator wrzuca lokalna zmienna i do obiektu w stercie zeby mozna bylo sie do niego odwolac. Pytanie kiedy tworzy ten obiekt? i jest deklarowane poza ciałem pętli tak więc obiekt jest tworzony również poza ciałem pętli.
Kazdy task dzieli ten obiekt.
Pierwszy task zakonczy petle a reszta tasków poprostu wyświetli 10.
Kompilator wrzuca lokalna zmienna i do obiektu w stercie.
i jest deklarowane poza ciałem
Kazdy task dzieli ten obiekt.
Pierwszy task zakonczy petle a reszta tasków poprostu wyświetli 10.