.NET

advertisement
Microsoft
.NET
Лекция 6:
Параллелизм
Меженин Михаил, кафедра "Системное программирование", ВМИ, ЮУрГУ, 2014
Microsoft
.NET
Параллелизм в .NET
• Потоки / Threads
• Задачи / Tasks
2
Microsoft
.NET
Threads
using System;
using System.Threading;
static void main()
{
Thread t = new Thread (DoSomething);
t.Start();
for (int i = 0; i < 1000; i++) Console.Write ("x");
}
static void DoSomething()
{
for (int i = 0; i < 1000; i++) Console.Write ("y");
}
3
Microsoft
.NET
Threads
using System;
using System.Threading;
static void main()
{
Thread t = new Thread (DoSomething);
t.Start();
t.Join();
// синхронизация
for (int i = 0; i < 1000; i++) Console.Write ("x");
}
static void DoSomething()
{
for (int i = 0; i < 1000; i++) Console.Write ("y");
Thread.Sleep (500);
// пауза
}
4
Microsoft
.NET
Параллелизм в .NET
Никакой безопасности!
• Локальные переменные у каждого потока свои
• Статические поля общие для всех потоков
• Экземпляры классов и их поля общие для всех
потоков
5
Microsoft
.NET
Threads
class ThreadTest
{
bool done;
static void main()
{
ThreadTest tt = new ThreadTest();
new Thread (t.DoSomething).Start();
tt.DoSomething();
}
void DoSomething()
{
if (!done) { Console.Write ("Done"); done = false; }
}
}
6
Threads
Microsoft
.NET
class ThreadTest
{
bool done;
object myLock = new object();
...
void DoSomething()
{
lock (myLock)
{
if (!done) { Console.Write ("Done"); done = false; }
}
}
}
7
Microsoft
.NET
Threads
using System;
using System.Threading;
static void main()
{
Thread t =
new Thread (() => DoSomething("X"));
t.Start();
}
// передача параметра
// с помощью лямбда-выражения
static void DoSomething(string s)
{
for (int i = 0; i < 1000; i++) Console.Write (s);
}
8
Microsoft
.NET
Threads
using System;
using System.Threading;
static void main()
{
Thread t = new Thread (() => DoSomething("X"));
t.IsBackground = true;
t.Start();
}
// фоновый поток
static void DoSomething(string s)
{
for (int i = 0; i < 1000; i++) Console.Write (s);
}
9
Microsoft
.NET
Thread Pool
Проблема: создание и удаление потоков – ресурсоемкая операция.
Решение: повторное использование потоков, хранящихся в пуле
void MyId() { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); }
for (int i = 0; i < 100; ++i)
new Thread(MyId).Start();
Thread.Sleep(5000);
for (int i = 0; i < 100; ++i)
ThreadPool.QueueUserWorkItem(d => MyId());
10
Microsoft
.NET
Tasks
Недостатки потоков:
• не возвращают результат
• нельзя проверить статус выполнения
Решение: новый API!
using System.Threading.Tasks;
var t1 = new Task(() => DoSomething("x")).Start();
t1.Wait();
// запуск
// ждем завершения
Task.Run(() => DoSomething("z"));
// запуск
Task<int> t = Task.Run(() => { return 3; });
var result = t.Result;
// задача с возвращаемым значением
// блокирующая проверка результата
11
Microsoft
.NET
Конвейер задач
// длительная задача
Task<int> primeNumberTask = Task.Run (() =>
Enumerable.Range (2, 3000000).Count (n =>
Enumerable.Range (2, (int)Math.Sqrt(n)-1).All (i => n % i > 0)));
// запуск делегата после завершения задачи
var awaiter = primeNumberTask.GetAwaiter();
awaiter.OnCompleted (() =>
{
int result = awaiter.GetResult();
Console.WriteLine (result); // Writes result
});
// запуск второй задачи после завершения первой
primeNumberTask.ContinueWith (antecedent =>
{
int result = antecedent.Result;
Console.WriteLine (result); // Writes 123
});
12
Microsoft
.NET
Асинхронные операции
Синхронные методы:
• блокируют поток
• возвращают управление после выполнения
• Console.WriteLine, Thread.Sleep
Асинхронные методы:
•
•
•
•
не блокируют поток
возвращают управление сразу после вызова
выполняются параллельно
Thread.Start, Task.Run, ____Async
await + async – простой способ последовательного написания кода,
работающего асинхронно
13
Microsoft
.NET
Асинхронные операции
var result = await expression;
statement(s);
var awaiter = expression.GetAwaiter();
awaiter.OnCompleted (() =>
{
var result= awaiter.GetResult();
statement(s);
);
14
Microsoft
.NET
Асинхронные операции
HttpClient client = new HttpClient();
Task<string> getStringTask =
client.GetStringAsync("http://msdn.microsoft.com"); // асинхронный метод
// выполнение занимает ~5c
// вызов GetStringAsync не блокирует выполнение - Console.ReadKey выполнится
Console.WriteLine("Loading...");
// выполнение будет остановлено, пока не выполнится GetStringAsync()
Console.WriteLine(getStringTask.Result);
Console.WriteLine("Done");
15
Microsoft
.NET
Асинхронные операции
// Вызываем асинхронный метод извне
var v = AccessTheWebAsync();
…
// Объявляем асинхронный метод
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
// Вызываем асинхронный метод GetStringAsync
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// Выполняем независимую от GetStringAsync работу
DoIndependentWork();
// Ждем выполнения задачи getStringTask и помещаем ее результат в urlContent
// Пока задача не выполнена, возвращаем управление в код, вызвавший AccessTheWebAsync()
string urlContents = await getStringTask;
return urlContents.Length;
}
16
Microsoft
.NET
Асинхронные операции
17
Microsoft
.NET
System.Threading.Tasks.Parallel
Простой параллелизм для циклов:
Parallel.For(0, 1000, i => DoWork(i));
Parallel.ForEach(collection, item => DoWork(item));
Parallel.Invoke(
() => Method1(),
() => Method2(),
() => Method3());
18
Microsoft
.NET
PLINQ
Простой параллелизм для LINQ:
"abcdef".AsParallel().Select (c => char.ToUpper(c)).ToArray();
19
Download