多线程与异步C
1.线程是进程的一部分,一个进程包括多个进程,此处多个进程皆可以访问进程共享的资源
1.1 此处多次运算结果不同
static void Main(string[] args)
{
const int total = 100000;
int count = 0;
var thread1 = new Thread(ThreadMethod);
var thread2 = new Thread(ThreadMethod);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Count{count}");
Console.ReadLine();
void ThreadMethod()
{
for (int i = 0; i < total; i++)
{
count++;
}
}
}
1.2 此处多次运算结果相同
static void Main(string[] args)
{
const int total = 100000;
object v = new object();
int count = 0;
var thread1 = new Thread(ThreadMethod);
var thread2 = new Thread(ThreadMethod);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Count{count}");
Console.ReadLine();
void ThreadMethod()
{
for (int i = 0; i < total; i++)
{
lock (v)
count++;
}
}
}
2.为什么需要多线程
1、批量重复任务同时进行–对于数组的元素进行相同且耗时的计算
2、多个不同任务同事进行,互不干扰
3、WPF的UI线程与IO任务
3.什么事线程池–预先被创建,可以重复使用,一个线程的生命周期很耗时
4.异步变成默认使用线程池
5.线程安全问题:
5.1多个线程访问共享资源时,对资源的访问不同表格导致不可语预期的问题
5.2
method1:同步机制(互斥锁):协调控制多个线程之间执行顺序语互斥访问共享资源
确定 线程之间按照特定顺序执行避免竞争与条件不一致
static void Main(string[] args)
{
const int total = 100000;
object v = new object();
int count = 0;
var thread1 = new Thread(ThreadMethod);
var thread2 = new Thread(ThreadMethod);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Count{count}");
Console.ReadLine();
void ThreadMethod()
{
for (int i = 0; i < total; i++)
{
lock (v)
count++;
}
}
}
method2:原子操作:执行过程中不会被中断 ---Interlocked
static void Main(string[] args)
{
const int total = 100000;
//object v = new object();
int count = 0;
var thread1 = new Thread(ThreadMethod);
var thread2 = new Thread(ThreadMethod);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine($"Count{count}");
Console.ReadLine();
void ThreadMethod()
{
for (int i = 0; i < total; i++)
{
Interlocked.Increment(ref count);
//lock (v)
count++;
}
}
}
6.常用的实现方式
1.线程
2.线程池
3.异步编程— asysn await
4.自带方法(并行操作)-- parallel plinq
4.1对比 常规操作
var inputs = Enumerable.Range(1, 20).ToArray();
var outputs = new int[inputs.Length];
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < inputs.Length; i++)
{
outputs[i] = HeavyArray(inputs[i]);
}
Console.WriteLine($"Elaspsed time:{sw.ElapsedMilliseconds}ms");
PrintArray(outputs);
Console.ReadLine();
int HeavyArray(int input)
{
Thread.Sleep(100);
return input * input;
}
void PrintArray<T>(T[] array)
{
for (int i = 0;i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
2080ms
4.2对比 并行操作--Parallel
```csharp
Parallel.For(0, inputs.Length, i =>
{
outputs[i] = HeavyArray(inputs[i]);
});
`420ms
4.3对比 并行操作--PLinq
/// question1:在数据量较大的情况下,可能会导致顺序问题(将数组长度设置为1000也未导致)
//解决方式outputs=inputs.AsParallel().AsOrdered().Select(x=>HeavyArray(x)).ToArray();
outputs=inputs.AsParallel().Select(x=>HeavyArray(x)).ToArray();
371ms
7 线程:
7.1:线程的创建
创建Thread实例,并传入ThreadStart委托–还可以配置线程(设置为后台线程)
前台线程:独立线程,后台线程:依附于前台线程(如main方法)
调用Thread.Start方法,还可以传参
7.2:线程的终止
Thread thread = new Thread((obj) =>
{
Console.WriteLine(obj);
for (int i = 0; i < 20; i++)
{
Thread.Sleep(200);
Console.WriteLine("Thread is still runing ...");
}
})
{ IsBackground = true,Priority = ThreadPriority.Normal};
thread.Start(123);
Console.WriteLine("In main thread,waiting for thread to finish");
thread.Join();
Console.WriteLine("Done.");
Console.ReadLine();
7.3:现成的挂起与恢复
Thread thread = new Thread((obj) =>
{
try {
Console.WriteLine(obj);
for (int i = 0; i < 20; i++)
{
Thread.Sleep(200);
Console.WriteLine("Thread is still runing ...");
}
} catch(ThreadInterruptedException )
{
}
finally {
Console.WriteLine("Thread is finishede");
}
})
{ IsBackground = true, Priority = ThreadPriority.Normal };
thread.Start(123);
Console.WriteLine("In main thread,waiting for thread to finish");
Thread.Sleep(1000);
thread.Interrupt();
thread.Join();
Console.WriteLine("Done.");
Console.ReadLine();
此处仅运行4次
try {
while (true)
{
}
//Console.WriteLine(obj);
//for (int i = 0; i < 20; i++)
//{
// Thread.Sleep(200);
// Console.WriteLine("Thread is still runing ...");
//}
} catch(ThreadInterruptedException )
{
}
finally {
Console.WriteLine("Thread is finishede");
}
这种情况下,thread不会interrupt 因为太忙了
此时
try {
while (true)
{
Thread.Sleep(0);
}
//Console.WriteLine(obj);
//for (int i = 0; i < 20; i++)
//{
// Thread.Sleep(200);
// Console.WriteLine("Thread is still runing ...");
//}
} catch(ThreadInterruptedException )
{
}
finally {
Console.WriteLine("Thread is finishede");
}
即可 interrupt
8线程安全与同步机制
Thread—Safety
8.0锁与信号量
1.lock&Monitor
2.Mutex -互斥锁
3.SemapPhone -旗语?线程间的同步 线程间通信
//第一个3 初始化3个 第二个3 max3个
Semaphore semaphore = new Semaphore(3, 3,ThreadName?);
outputs = inputs.AsParallel().AsOrdered().Select(x => HeavyArray(x)).ToArray();
Console.WriteLine($"Elaspsed time:{sw.ElapsedMilliseconds}ms");
PrintArray(outputs);
//此处需要销毁掉
semaphore.Dispose();
Console.ReadLine();
int HeavyArray(int input)
{
//等待信号量
semaphore.WaitOne();
Thread.Sleep(100);
//释放信号量
semaphore.Release();
return input * input;
}
此时耗时会增加–避免并行过快
4.WaitHandle
4.1-- manualResetEvent
4.2–AutoResetEvent
5.ReadWriterLock --读写锁 只有一个writer在写
8.1 轻量锁
semaPhoneSlim --存在异步版本
ManuaReseEventSlim
ReaderWriterLockSlim
8.2 原子操作