diff --git a/Docs/Jupyter笔记.2.2.托管线程.ipynb b/Docs/Jupyter笔记.2.2.托管线程.ipynb index 5d028e5..f39535b 100644 --- a/Docs/Jupyter笔记.2.2.托管线程.ipynb +++ b/Docs/Jupyter笔记.2.2.托管线程.ipynb @@ -1008,6 +1008,60 @@ ], "languageName": null, "name": "vscode" + }, + { + "aliases": [], + "name": ".NET" + }, + { + "aliases": [ + "f#", + "F#" + ], + "languageName": "F#", + "name": "fsharp" + }, + { + "aliases": [], + "languageName": "HTML", + "name": "html" + }, + { + "aliases": [ + "js" + ], + "languageName": "JavaScript", + "name": "javascript" + }, + { + "aliases": [], + "languageName": "KQL", + "name": "kql" + }, + { + "aliases": [], + "languageName": "Mermaid", + "name": "mermaid" + }, + { + "aliases": [ + "powershell" + ], + "languageName": "PowerShell", + "name": "pwsh" + }, + { + "aliases": [], + "languageName": "SQL", + "name": "sql" + }, + { + "aliases": [], + "name": "value" + }, + { + "aliases": [], + "name": "webview" } ] } diff --git a/Docs/Jupyter笔记.2.3.抢占与合作模式.ipynb b/Docs/Jupyter笔记.2.3.抢占与合作模式.ipynb index 4620d88..f16527e 100644 --- a/Docs/Jupyter笔记.2.3.抢占与合作模式.ipynb +++ b/Docs/Jupyter笔记.2.3.抢占与合作模式.ipynb @@ -28,8 +28,11 @@ } }, "source": [ - "学习 Thread,执行各种 Thread 操作。 \n", - "特别注意:NoteBook 本身的运行线程是后台线程,不会等待由其创建的线程执行结束。与控制台等应用有区别。 " + ".Net中,托管线程分为抢占模式和合作模式;区分这两种模式,主要是为了GC的实现。 \n", + "\n", + "处于合作模式的线程可以自由地访问托管堆上的对象;处理抢占模式的线程则不能访问托管堆上的对象,如果需要访问则必须等待GC结束并切换到合作模式。因为托管代码随时需要访问托管堆,所以托管代码必须在合作模式下运行,而非托管代码则没有这个限制。进入抢占模式后,托管代码暂停执行而非托管代码可以继续做与.Net对象无关的处理。 \n", + "\n", + "模式切换分为主动切换和被动切换" ] }, { @@ -44,33 +47,7 @@ } }, "source": [ - "## 全局设置,语言设置、Nuget包引用、空间引用等" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - }, - "vscode": { - "languageId": "polyglot-notebook" - } - }, - "outputs": [], - "source": [ - "//全局设置\n", - "#!csharp\n", - "using System.Threading;\n", - "using System.Threading.Channels;\n", - "using System.Threading.Tasks;\n", - "\n", - "//全局变量\n", - "var noteBookThreadDesc = \"NoteBook线程\";" + "GC安全点" ] } ], diff --git a/Docs/Jupyter笔记.2.4.线程本地存储.ipynb b/Docs/Jupyter笔记.2.4.线程本地存储.ipynb new file mode 100644 index 0000000..6625e90 --- /dev/null +++ b/Docs/Jupyter笔记.2.4.线程本地存储.ipynb @@ -0,0 +1,289 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "source": [ + "线程本地存储\n", + "============================== " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "source": [ + "线程本地存储(Thread Local Storge,简称TLS)机制用于实现按线程隔离的线程本地变量,对于同一个线程本地变量,各个线程分别有独立的值,修改的值只能修改的线程可见。
\n", + "\n", + "线程要地存储可以分为原生实现与托管实现,原生实现指的是调用操作系统提供的接口访问原生线程对应的线程本地存储,而托管实现指的是调用.net提供的接口访问托管线程对应的线程本地存储。
\n", + "\n", + "原生实现,在Windows和linux上的实现不同,但同样都是调用系统提供的接口。
" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "source": [ + "## 全局设置,语言设置、Nuget包引用、空间引用等" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [], + "source": [ + "//全局设置\n", + "#!csharp\n", + "using System.Threading;\n", + "using System.Threading.Channels;\n", + "using System.Threading.Tasks;\n", + "\n", + "//全局变量\n", + "var noteBookThreadDesc = \"NoteBook线程\";\n", + "\n", + "//全局方法\n", + "//显示线程信息\n", + "public void ShowThreadInfo(Thread showThread=null, string describe = null)\n", + "{\n", + " if(showThread == null)\n", + " {\n", + " showThread = Thread.CurrentThread;\n", + " }\n", + "\n", + " if(string.IsNullOrWhiteSpace(describe))\n", + " {\n", + " describe = showThread.Name == null ? \"无名\" : showThread.Name;\n", + " }\n", + "\n", + " Console.WriteLine($\"{describe}线程ID:{showThread.ManagedThreadId} \");\n", + " Console.WriteLine($\"{describe}线程名:{showThread.Name} \");\n", + " Console.WriteLine($\"{describe}线程状态:{showThread.ThreadState} \");\n", + " Console.WriteLine($\"{describe}线程模式:{showThread.GetApartmentState()} \");\n", + " Console.WriteLine($\"{describe}激活:{(showThread.IsAlive ? \"活动\" : \"非活动\")} \");\n", + " Console.WriteLine($\"{describe}线程池线程:{(showThread.IsThreadPoolThread ? \"是的\" : \"否\")} \");\n", + " Console.WriteLine($\"{describe}后台线:{(showThread.IsBackground ? \"是的\" : \"不是\")} \");\n", + " Console.WriteLine($\"{describe}区域:{showThread.CurrentCulture}\");\n", + " Console.WriteLine($\"{describe}UI区域:{showThread.CurrentUICulture}\");\n", + " Console.WriteLine($\"{describe}优先级:{showThread.Priority}\");\n", + "}\n", + "\n", + "//显示线程状态\n", + "public void ShowThreadState(Thread showThread=null, string describe = null)\n", + "{\n", + " if(showThread == null)\n", + " {\n", + " showThread = Thread.CurrentThread;\n", + " }\n", + "\n", + " if(string.IsNullOrWhiteSpace(describe))\n", + " {\n", + " describe = showThread.Name == null ? \"无名\" : showThread.Name;\n", + " }\n", + " Console.WriteLine($\"{describe}线程状态:{showThread.ThreadState} \");\n", + "}" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "source": [ + "## ThreadStatic Attribute 属性的实现" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "source": [ + "在 .NET 中标记了[ThreadStatic]特性的全局变量就是托管线程本地变量。
\n", + "\n", + "在 .NET 中,每个托管对象都关联一个TLB(Thread Local Block)表,TLB表以 AppDomain ID 为索引保存 TLM(Thread Local Module)表,TLM表以模块ID为索引保存托管线程本地存储空间的开始地址。当 .NET 运行时加载一个程序集时,会枚举程序集中的模块与模块中的全局变量,然后按是否线程本地变量分成两部分,非线程本地变量会保存在 AppDomain 对应的高频堆中;而线程本地变量只计算偏移值,存储空间会在首次访问时分配。 " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [], + "source": [ + "{ //隔离代码\n", + "\n", + " Console.WriteLine(\"花括号隔离代码,避免上下段互相影响!\");\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [], + "source": [ + "public class Demo\n", + "{\n", + "\n", + " \n", + "}\n", + "{\n", + "\n", + "\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [ + "c#", + "C#" + ], + "languageName": "C#", + "name": "csharp" + }, + { + "aliases": [ + "frontend" + ], + "languageName": null, + "name": "vscode" + }, + { + "aliases": [], + "languageName": null, + "name": ".NET" + }, + { + "aliases": [ + "f#", + "F#" + ], + "languageName": "F#", + "name": "fsharp" + }, + { + "aliases": [], + "languageName": "HTML", + "name": "html" + }, + { + "aliases": [ + "js" + ], + "languageName": "JavaScript", + "name": "javascript" + }, + { + "aliases": [], + "languageName": "KQL", + "name": "kql" + }, + { + "aliases": [], + "languageName": "Mermaid", + "name": "mermaid" + }, + { + "aliases": [ + "powershell" + ], + "languageName": "PowerShell", + "name": "pwsh" + }, + { + "aliases": [], + "languageName": "SQL", + "name": "sql" + }, + { + "aliases": [], + "languageName": null, + "name": "value" + }, + { + "aliases": [], + "name": "webview" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Docs/assets/images/LifeCycle2.png b/Docs/assets/images/LifeCycle2.png new file mode 100644 index 0000000..ac97918 Binary files /dev/null and b/Docs/assets/images/LifeCycle2.png differ diff --git a/Docs/assets/images/LifeCycle3.png b/Docs/assets/images/LifeCycle3.png new file mode 100644 index 0000000..655f609 Binary files /dev/null and b/Docs/assets/images/LifeCycle3.png differ diff --git a/Docs/assets/images/LifeCycle4.png b/Docs/assets/images/LifeCycle4.png new file mode 100644 index 0000000..1b8e0cf Binary files /dev/null and b/Docs/assets/images/LifeCycle4.png differ diff --git a/Docs/并发与并行.md b/Docs/并发与并行.md index 95c5682..f904b4f 100644 --- a/Docs/并发与并行.md +++ b/Docs/并发与并行.md @@ -1,21 +1,21 @@ # **并行与并发** -# 概念: +## 概念 **并发**:同时发生(申请):申请者(应用)将多个任务`同时或同一时间间隔`向`单一执行者(`CPU)申请执行;执行者同时接收或同时存在多外执行任务,`交替(非同时)执行`,因执行的非常快,`在申请方看来,是多个申请同时得到执行`。 **并行**:同时执行:申请者(应用)将多个任务`同一时刻`向`多个执行者(`CPU)申请执行;多个执行者`同时接收并同时执行`。 -## 区别: +## 区别 -+ 对象不同:并发针对单一执行者(CPU),并行针对多个执行者(CPU) ++ **对象不同**:并发针对单一执行者(CPU),并行针对多个执行者(CPU) -+ 时间不同:并发指同一时间间隔,申请者宏观上看任务是同时得到处理(因为执者执行的非常快,交替执行的时间片很小),执行者微观上是交替执行(一个执行者,同一时刻只能执行一个任务);并行指同一时刻,多个执行者(CPU)同时处理多个任务(其中每个处理者处理一个任务)。 ++ **时间不同**:并发指同一时间间隔,申请者宏观上看任务是同时得到处理(因为执者执行的非常快,交替执行的时间片很小),执行者微观上是交替执行(一个执行者,同一时刻只能执行一个任务);并行指同一时刻,多个执行者(CPU)同时处理多个任务(其中每个处理者处理一个任务)。 -+ 含义不同:并发同一执行者,宏观上同时处理多个任务;并行是多个执行者,微观上同一时刻,执行多个任务。 ++ **含义不同**:并发同一执行者,宏观上同时处理多个任务;并行是多个执行者,微观上同一时刻,执行多个任务。 -## 联系: +## 联系 -+ 单核 CPU:只能并发不能并行;提高响应能力。 ++ **单核 CPU**:只能并发不能并行;提高响应能力。 -+ 多核 CPU:多核上可以并行,提高吞吐量;同时在每个核心上可能并发,提高响应能力。 ++ **多核 CPU**:多核上可以并行,提高吞吐量;同时在每个核心上可能并发,提高响应能力。 diff --git a/MultiThreadingStudy.xUnitTest/ProsessTest.cs b/MultiThreadingStudy.xUnitTest/ProsessTest.cs new file mode 100644 index 0000000..1d8533d --- /dev/null +++ b/MultiThreadingStudy.xUnitTest/ProsessTest.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MultiThreadingStudy.xUnitTest +{ + /// + /// 进程测试 + /// + public class ProsessTest + { + private ITestOutputHelper _output; + public ProsessTest(ITestOutputHelper testOutput) + { + _output = testOutput; + } + + [Fact] + public void Test() + { + ShowProcessInfo(); + } + + private void ShowProcessInfo(Process? process = null) + { + if (process == null) { process = Process.GetCurrentProcess(); } + + _output.WriteLine($"进程名:{ process.ProcessName }"); + _output.WriteLine($"进程Id:{ process.Id }"); + _output.WriteLine($"进程SessionId:{ process.SessionId }"); + _output.WriteLine($"机器名:{ process.MachineName }"); + _output.WriteLine($"基本优先级:{ process.BasePriority }"); + _output.WriteLine($"是否RaisingEvents:{ process.EnableRaisingEvents }"); + + _output.WriteLine($"进程状态:{ (process.HasExited ? "已退出":"运行中")}"); + if (process.HasExited) + { + _output.WriteLine($"退出码:{process.ExitCode}"); + _output.WriteLine($"退出时间:{process.ExitTime}"); + } + + _output.WriteLine($"句柄数:{ process.HandleCount }"); + _output.WriteLine($"页内存大小:{ process.PagedMemorySize64 }"); + _output.WriteLine($"页系统内存大小:{ process.PagedSystemMemorySize64 }"); + _output.WriteLine($"峰值虚拟内存:{ process.PeakVirtualMemorySize64 }"); + _output.WriteLine($"峰值工作内存:{ process.PeakWorkingSet64 }"); + _output.WriteLine($"进程名:{ process.PriorityBoostEnabled }"); + _output.WriteLine($"专用内存大小:{ process.PrivateMemorySize64 }"); + //_output.WriteLine($"开始信息:{ process.StartInfo }"); + _output.WriteLine($"开始时间:{ process.StartTime }"); + _output.WriteLine($"线程数量:{ process.Threads.Count }"); + _output.WriteLine($"总进程时间量:{ process.TotalProcessorTime }"); + _output.WriteLine($"用户进程时间量:{ process.UserProcessorTime }"); + } + } +} diff --git a/MultiThreadingStudy.xUnitTest/ThreadLocalStorageTest.cs b/MultiThreadingStudy.xUnitTest/ThreadLocalStorageTest.cs new file mode 100644 index 0000000..255e2af --- /dev/null +++ b/MultiThreadingStudy.xUnitTest/ThreadLocalStorageTest.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MultiThreadingStudy.xUnitTest +{ + /// + /// 线程的本地存储 + /// + public class ThreadLocalStorageTest + { + public ThreadLocalStorageTest() + { + } + } +} diff --git a/MultiThreadingStudy.xUnitTest/Usings.cs b/MultiThreadingStudy.xUnitTest/Usings.cs index 2dfbf26..c0e27c7 100644 --- a/MultiThreadingStudy.xUnitTest/Usings.cs +++ b/MultiThreadingStudy.xUnitTest/Usings.cs @@ -1,5 +1,10 @@ global using Xunit; +global using Xunit.Abstractions; +global using Xunit.Extensions; +global using Xunit.Sdk; global using System.Threading; global using System.Threading.Channels; -global using System.Threading.Tasks; \ No newline at end of file +global using System.Threading.Tasks; + +global using System.Diagnostics; \ No newline at end of file