线程学习--Threads
-
线程
#region Threads
/// <summary>
/// 1.0 1.1
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnThreads_Click(object sender, EventArgs e)
{
Console.WriteLine($"****************btnThreads_Click Start " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
//Action action = () => this.DoSomethingLong("btnThreads_Click");
ThreadStart threadStart = () => this.DoSomethingLong("btnThreads_Click");
Thread thread = new Thread(threadStart);
thread.Start();
//thread.Suspend(); // 线程挂起 (不推荐,抛弃)
//thread.Resume(); // 唤醒线程 (不推荐,抛弃)
//thread.Abort(); // 销毁,方式是抛异常 (也不建议使用) 不一定及时、有些动作发出收不回来
//Thread.ResetAbort(); // 取消异常
Console.WriteLine($"****************btnThreads_Click End " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}
#endregion
- 线程等待
thread.Join(); // 当前线程等待Thread完成
thread.Join(500); // 最多等待500ms
while(thread.ThreadState != ThreadState.Stopped)
{
Thread.Sleep(100); // 当前线程休息100ms
}
- 前后台线程
Console.WriteLine(thread.IsBackground);
// 默认是前台线程,启动之后一定要完成任务的,阻止进程退出
thread.IsBackground = true; // 指定后台线程:随着进程退出
- 线程优先级
thread.Priority = ThreadPriority.Highest;
// CPU会优先执行,但不代表说Highest就最先完成
-
ThreadPool线程池
ThreadPool用法
#region ThreadPool
/// <summary>
/// 2.0 享元模式 数据库连接池
/// 1.thread提供了太多API
/// 2.无限使用线程,加以限制
/// 3.重用线程,避免重复的创建和销毁
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnThreadPool_Click(object sender, EventArgs e)
{
Console.WriteLine($"****************btnThreadPool_Click Start " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
ThreadPool.QueueUserWorkItem(t => this.DoSomethingLong("btnThreadPool_Click"));
ThreadPool.SetMaxThreads(16, 16);
ThreadPool.SetMinThreads(8, 8);
{
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
//辅助线程的最大数目 异步线程的最大数目
Console.WriteLine($"workerThreads={workerThreads}
completionPortThreads={completionPortThreads}");
}
{
ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
}
Console.WriteLine($"****************btnThreadPool_Click End " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}
#endregion
- ThreadPool线程等待
// ThreadPool啥都没有 如何等待?
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
// false WaitOne等待 Set true
// true WaitOne直接过去 reset false WaitOne等待
ThreadPool.QueueUserWorkItem(t =>
{
this.DoSomethingLong("btnThreadPool_Click");
manualResetEvent.Set(); // 置成true
// manualResetEvent.Reset(); // 置成false
});
manualResetEvent.WaitOne();
也有缺点,一般来说,不要阻塞线程池的线程
// 启动子线程计算 -- 完成委托后,该线程去执行后续回调委托
private void ThreadWithCallback(Action act, Action callback)
{
Thread thread = new Thread(() => {
act.Invoke();
callback.Invoke();
});
thread.Start();
}
this.ThreadWithCallback(() =>
Console.WriteLine($"这里是action
{Thread.CurrentThread.ManagedThreadId.ToString("00")}")
, () =>
Console.WriteLine($"这里是callback
{Thread.CurrentThread.ManagedThreadId.ToString("00")}"));
// 带返回的异步调用 需要获取返回值
private Func<T> ThreadWithReturn<T> (Func<T> func)
{
T t = default(T);
Thread thread = new Thread(()=>
{
t = func.Invoke();
});
thread.Start();
return () =>
{
//while (thread.ThreadState != ThreadState.Stopped)
//{
// Thread.Sleep(200);
//}
thread.Join();
return t;
};
}
Func<int> func = this.ThreadWithReturn<int>(() =>
{
Thread.Sleep(2000);
return DateTime.Now.Millisecond;
});
Console.WriteLine("12324546576586789789");
int iResult = func.Invoke();
Console.WriteLine(iResult);
-
Task
#region Task
/// <summary>
/// 3.0 Task 是基于ThreadPool
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnTask_Click(object sender, EventArgs e)
{
Console.WriteLine($"****************btnTask_Click Start " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
Task.Run(() => this.DoSomethingLong("btnTask_Click1"));
Task.Run(() => this.DoSomethingLong("btnTask_Click2"));
TaskFactory taskFactory = Task.Factory;// 4.0
taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click3"));
new Task(() => this.DoSomethingLong("btnTask_Click4")).Start();
Console.WriteLine($"****************btnTask_Click End " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}
#endregion
- 什么时候用多线程?
任务能并发进行:提升速度 优化体验
List<Task> taskList = new List<Task>();
Console.WriteLine($"项目经理启动一个项目。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
Console.WriteLine($"前置准备工作。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
Console.WriteLine($"开始编程。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
taskList.Add(Task.Run(() => this.Coding("小张", "Client")));
taskList.Add(Task.Run(() => this.Coding("小王", "Portal")));
taskList.Add(Task.Run(() => this.Coding("小李", "Service")));
taskList.Add(Task.Run(() => this.Coding("小陈", "Jump")));
taskList.Add(Task.Run(() => this.Coding("小爱", "Monitor")));
// 一个业务查询操作有多个数据源,首页-多线程并发-拿到全部数据后才能返回 WaitAll
// 一个商品搜索操作有多个数据源,商品搜索- 多个数据源- 多线程并发-只需要一个结果即可 WaitAny
// 阻塞:需要完成后再继续
Task.WaitAny(taskList.ToArray()); // 会阻塞当前线程,等着某个任务完成后,才进入下一行
Console.WriteLine($"完成里程碑【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
// 多线程加快速度,但全部任务完成后,才能执行的操作
Task.WaitAll(taskList.ToArray());// 会阻塞当前线程,等着全部任务都完成后,才进入下一行
Task.WaitAll(taskList.ToArray(), 1000);
Console.WriteLine("等待1s后,执行动作");
Console.WriteLine($"甲方验收。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
/// <summary>
/// 编码做项目
/// </summary>
/// <param name="name"></param>
/// <param name="project"></param>
private void Coding(string name, string project)
{
Console.WriteLine($"****************Coding {name} Start {project} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
long lResult = 0;
for (int i = 0; i < 1000000000; i++)
{
lResult += i;
}
//Thread.Sleep(2000);
Console.WriteLine($"****************Coding {name} End {project} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
}
以上都会阻塞线程,下面的不阻塞:
TaskFactory taskFactory = new TaskFactory();
taskFactory.ContinueWhenAll(taskList.ToArray(), tList =>
{
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
{
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
Task.WhenAny(taskList.ToArray()).ContinueWith(t =>
{
Console.WriteLine($"得意的笑。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
Task.WhenAll(taskList.ToArray()).ContinueWith(t =>
{
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
- 完成10000个任务 但是只要10个线程
List<int> list = new List<int>();
for (int i = 0; i < 10000; i++)
{
list.Add(i);
}
// 完成10000个任务 但是只要10个线程
Action<int> action = i =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00"));
Thread.Sleep(new Random(i).Next(100, 300));
};
List<Task> taskList = new List<Task>();
foreach (var item in list)
{
int k = item;
Task.Run(() => action.Invoke(k));
if (taskList.Count > 10)
{
Task.WaitAny(taskList.ToArray());
taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
}
}
Task.WhenAll(taskList.ToArray());
想知道线程是由哪个完成的
TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>();
taskList.Add(taskFactory.StartNew(o => this.Coding("爱书客", "Client"), "爱书客"));
taskList.Add(taskFactory.StartNew(o => this.Coding("风动寂野", "Portal"), "风动寂野"));
taskList.Add(taskFactory.StartNew(o => this.Coding("笑看风云", "Service"), "笑看风云"));
taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
{
Console.WriteLine(t.AsyncState);
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
taskFactory.ContinueWhenAll(taskList.ToArray(), tList =>
{
Console.WriteLine(tList[0].AsyncState);
Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
Task.Run(
() =>
{
Task.WaitAny(taskList.ToArray());//会阻塞当前线程,等着某个任务完成后,才进入下一行 卡界面
//Task.WaitAny(taskList.ToArray(), 1000);
Console.WriteLine($"完成里程碑 【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
//多线程加快速度,但是全部任务完成后,才能执行的操作
Task.WaitAll(taskList.ToArray());//会阻塞当前线程,等着全部任务完成后,才进入下一行 卡界面
Console.WriteLine($"告诉甲方验收,上线使用【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
});
- 延迟
{
Task.Delay(1000);//延迟 不会卡
Thread.Sleep(1000);//等待 卡
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Thread.Sleep(2000);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
}
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task.Delay(2000).ContinueWith(t =>
{
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
});
}
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task.Run(() =>
{
Thread.Sleep(2000);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
});
}
-
并行编程
#region Parallel
/// <summary>
/// 并行编程 在Task的基础上做了封装 4.5
/// Parallel 卡界面,调用parallel线程参与计算,节约了一个线程
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnParallel_Click(object sender, EventArgs e)
{
Console.WriteLine($"****************btnParallel_Click Start " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
//Parallel.Invoke(() => this.Coding("爱书客", "Client")
// , () => this.Coding("风动寂野", "Portal")
// , () => this.Coding("笑看风云", "Service"));
//Parallel.For(0, 5, i => this.Coding("爱书客", "Client" + i));
//Parallel.ForEach(new string[] { "0","1","2","3","4"}, i => this.Coding("爱书客", "Client" + i));
Console.WriteLine($"****************btnParallel_Click End " +
$"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
$"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}
#endregion
parallelOptions 可以控制并发数量:
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0, 10, parallelOptions, i => this.Coding("爱书客", "Client" + i));
Task.Run(() =>
{
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 3;
Parallel.For(0, 10, parallelOptions, i => this.Coding("爱书客", "Client" + i));
});
本文来自博客园,作者:一纸年华,转载请注明原文链接:https://www.cnblogs.com/nullcodeworld/p/18210659