.net core 高级进阶 1

news/2024/9/8 5:20:04/

Thread/ThreadPool/Task/TaskFactory

1、进程和线程的区别

进程是正在执行中的程序,进程中执行的每个任务即为一个线程;
线程属于进程;线程离不开委托;

NetFramework 1.0版本:
线程Thread是C#语言对操作计算机线程的一个封装类;

线程代码讲解

Thread thread = new Thread ();thread.Suspend();//暂停
thread.Resume();//让暂停的线程继续执行thread.Abort();//终止线程
thread.ResetAbort();//终止的线程继续执行;静态方法;Thread.Sleep();//等待
thread.Join(2000);//限时等待,过时不候;while(thread.ThreadState != ThreadState.Stopped)
{Thread.Sleep(2000);
}//线程的优先级
thread.Priority = ThreadPriority.Highest;//最好不要通过这种方式设置;只是从概念上增加优先级,计算机整体的具体优先级还是以实际为准;thread.IsBackgroud = true//设置后台线程;当进程关闭,线程随之取消;

2、单线程

按照顺序一个一个执行

3、多线程

同时工作 同时工作 同时工作 同时工作 同时工作 同时工作
1.效率高
2.消耗资源高
3.各线程执行顺序 难以控制

4、多线程回调

如何控制 多线程 的执行顺序 --> 回调 (多线程实例:线程 2 需要使用 线程 1 中的结果)

//Thread中没有控制线程执行顺序的方法;但可以自己通过封装的方式实现线程回调//多线程实例:线程 2 需要使用 线程 1 中的结果;
private void main()
{//1.普通多线程按顺序执行ThreadStart threadStart = new ThreadStart (() =>Console.WriteLine("线程1"););Action action = () => Console.WriteLine("线程2");This.ThradWithCallBack(threadStart, action);//2.如果需要有返回值呢?Func<int> func= () =>   //定义了一个委托{return DateTime.Now.Year;};//int iResult = ThradWithReturn(func);Func<int> fResult = ThradWithReturn(func);int iResult = fResult.Invoke();}//使用自定义封装方式老进行多线程回调
private void ThradWithCallBack(ThreadStart threadStart,Action action)
{//开启一个线程去执行传进来的两个线程;ThreadStart start = () =>{threadStart.Invoke();//去执行线程action.Invoke();};new Thread(start).Start();
}private Func<T> ThradWithReturn<T>(Func<int> func)
{T t = default(T);ThreadStart thradStart = () =>{t = func.Invoke();}ThreadStart threadStart = new ThreadStart (thradStart);threadStart.Start();return new Func<T>(() => {//threadStart.join(1000);//可以添加限时等待,return t;});
}

5、线程池 ThreadPool

线程池中有很多创建好的线程,用的时候拿出来用,用完了或者不用了,就放回线程池;


private void main()
{Console.WriteLine("线程1-1");//1.普通多线程按顺序执行{WaitCallback waitCallback = new WaitCallback( o =>Console.WriteLine("线程2-1");)ThreadPool.QueueUserWorkItem(waitCallback,"线程池");//从线程池中获取线程}//2.回调(线程等待){ManualResetEvent mre = new ManualResetEvent(false);//设置中间变量mre的默认值为falseThreadPool.QueueUserWorkItem(o => {Console.WriteLine("线程o")mre.Set();});//从线程池中获取线程//线程等待mre.WaitOne();//等待上一个线程先执行;}Console.WriteLine("线程1-1");
}

6、Task

6.1 Task与TaskFactory 的区别?

Task是对线程的一个封装类,实际上是一个线程
TaskFactory :创建Task的地方;

总结:Task来自于ThreadPool


private void main()
{Console.WriteLine("线程1-1");//1.如何申请一个线程{Task task = new Task(()=>{Console.WriteLine("线程2");});task.Start();}{TaskFactory taskFactory = new TaskFactory();taskFactory.StartNew(() => {Console.WriteLine("线程3");});}{//申请线程ThreadPool.SetMaxThreads(8, 8);//设置最大线程数量,【全局的】;List<int> thradIds= new List<int>();List<Task> tasklist = new List<Task>();for(int i=0; i<50; i++){tasklist.Add(Task.Run(() => {//申请一个线程thradIds.Add("获取当前线程Id");Console.WriteLine("当前线程Id");}))}Task.WaitAll(tasklist.ToArray());//阻塞主线程,等待所有子线程完成任务后,主线程再继续;(会导致主界面卡顿)int iResult = threadIds.Distinct().Count();//iResult=8;------------------------//总结:Task来自于ThreadPool--------}{List<Task> tasklist = new List<Task>();//单线程进行讲课Teach("课程1");//Teach() 用户自定义方法Teach("课程2");Teach("课程3");Teach("课程4");Console.WriteLine("课程教学完毕,准备分配任务编写代码...");//讲完课之后,让多个人同时去编码(多线程)TaskFactory taskFactory = Task.Factory();tasklist.Add(taskFactory.StaretNew(() => Coding("同学1","后台管理")));//Coding()用户自定义方法;tasklist.Add(taskFactory.StaretNew(() => Coding("同学2","前台页面")));tasklist.Add(taskFactory.StaretNew(() => Coding("同学3","微服务架构的搭建")));tasklist.Add(taskFactory.StaretNew(() => Coding("同学4","小程序接口实现")));//所有同学都顺利完成,我们准备聚个餐,K个歌...{//1.Task.WaitAll()Task.WaitAll(tasklist.ToArray());//等待所有同学完成工作后,主线程才继续执行;会造成主线程中界面卡顿;Console.WriteLine($"所有项目搭建完毕,我们准备聚个餐,K个歌...");}{//2.taskFactory.ContinueWhenAll()//使用了回调,在一堆任务执行完毕之后,去申请一个新的线程来执行新的动作;taskFactory.ContinueWhenAll(tasklist.ToArray(),t => Console.WriteLine($"所有项目搭建完毕,我们准备聚个餐,K个歌..."));}{//3.taskFactory.ContinueWhenAny()当执行了某一个任务时,主线程就会继续执行了;taskFactory.ContinueWhenAny(tasklist.ToArray(),t => Console.WriteLine($"当某一个同学完成工作了,老师就准备环境的搭建"));}{//4.如何控制线程数量;//为什么要限制线程数量?因为要合理分配计算机系统资源;List<Task> tasklist = new List<Task>();for(int i=0 ; i<10000 ; i++){int k = 1;if(tasklist.Count(t => t.Status == TaskStatus.Running) >= 20)//如果线程数量为20了,则主线程开始阻塞,且必须等到有一个线程完成之后,再继续主线程{Task.WaitAny(tasklist.ToArray());//下面这句代码自行调试和添加条件;暂未修改tasklist = tasklist.Where(t => t.Status != TaskStatus.RanToCompletion && t.Status != TaskStatus.Canceled && t.Status != TaskStatus.Faulted).ToList();//保留未执行完毕的线程;RanToCompletion()是否完成;Canceled取消;Faulted异常;}//添加一个新的线程tasklist.Add(Task.Run(()={Thread.Sleep(2000);Console.WriteLine($"This is new Thread.");//容易直接卡死计算机;}));Console.WriteLine($"线程数量为={tasklist.Count()}");}}{//5.如果新申请的线程里面有返回值怎么获取呢?Func<int> func = ()=>{ //定义一个委托delegate,返回当前年份;Thread.Sleep(3000);return DateTime.Now.Year;};Task<int> task = new Task<int>(func);task.Start();int i = task.Result;//这里会阻塞页面}}Console.WriteLine("线程1-1");
}

Task.WaitAll()
与taskFactory.ContinueWhenAll()类似,但是Task.WaitAll()会阻塞主线程,造成卡顿;当所有线程完毕之后,主线程继续;

taskFactory.WaitAny()
主线程进行阻塞,当有一个线程执行完毕后,主线程继续执行;

taskFactory.ContinueWhenAll()
举例:某个主页会涉及到多个数据,数据1来源于DB,数据2来源于第三方,数据3来源于其他DB;
传统顺序:一个一个进行查找,比较耗时;如果每一步平均耗时1秒,那么传统顺序会耗时3秒
使用ContinueWhenAll的时候,系统会进行同时查找,总耗时为1秒;提高查询效率;

taskFactory.ContinueWhenAny()

举例:查找某个数据;
传统思路查找顺序:(1)找缓存 --> (2)找接口 --> (3)找DB
使用ContinueWhenAny的时候,创建了多个线程去不同的地方同时进行查找,当有一个完成查找之后,就可直接返回数据,页面进行相应;

7、表达式目录树 Expression<>

表达式目录树 实际上是一个数据结构(二叉树)。

为什么使用表达式目录树?
答:表达式目录树 – 动态的
初级阶段:数据库查询的时候,都是拼接SQL语句(多一个条件就拼接一个查询字符串);
现在:使用LinqToSql;

Expression<Func<int, int, int>> ex1 =  (m, n) => m * n + 2 + 3;//如下图所示

在这里插入图片描述

//1.委托
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;//(m, n) => m * n + 2实际上是一个匿名方法;Func<返回值, m, n>
var func1 = exp.Compile();
int IResult = func1.Invoke(1, 2);//2.表达式目录
var peopleQuery = new List<People>().AsQueryable();
Expression<Func<People, bool>> expression = p => p.Id.Tostring().Equals("5");
PeopleQuery.Where(expression);
//进行编译
//通过ILspy反编译
//看中间语言,经过解析后,可以如下表示;
ParameterExperssion p = Experssion.Paramter(typeof(People),"p");
FieldInfo fieldId = typeof(People).GetField("Id");
MemberExperssion exp = Experssion.Field(p,fieldId);
MethodInfo toString = Typeof(People).GetField("Id");
var toString = Experssion.Call(exp ,toString ,Array.Empty<Expression>());
MethodInfo equals = typeof(string).GetMethod("Equals",new Type[] {typeof(string)});
Experssion expressionContant = Expression.Contant("5");var equalExp = Expression.Call(toStringExp,equals, new Expression[]{expressionContant
});//equalExp == p.Id.Tostring().Equals("5")Expression<Func<People, bool>> expression = Expression.Lambda<Func<People, bool>>(equalExp, new ParamterExpression[]{p
});//expression == p => p.Id.Tostring().Equals("5")bool bResult = experssion.Compile().Invoke(new People(){Id = 5});//experssion.Compile()定义了一个委托
{}

7.1 表达式目录树是如何拆解成Sql语句被数据库识别

//ExpressionVisitor//带有Visitor的是访问者模式//ExpressionVisitor.Visit()方法是访问表达式目录树的入口:1、首先会判断是什么类型的表达式目录(And、GreaterThan);2、会自动的调用到更加专业的方法中去进一步访问(ExpressionVisitor.多个具体分方法名());
//ExpressionVisitor.多个具体分方法名()//转换成SQL能识别的;例1:将 C#中的 && 转换成 SQL 中的 and;例2:程序中需要只允许减号-的存在,一般这个时候,需要我们去重写微软封装的方法,通过人为的判断,将+号全部改成减-号;我们可以自己定义一个类,来继承自ExpressionVisitor,然后重写封装的方法;
public static main()
{Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;//定义了一个表达式目录树;OperationsVisitor visitor = new OperationsVisitor();Expression expNew = visitor.Modify(exp);
}public class OperationsVisitor : ExpressionVisitor
{public Expression Modify(Expression expression){return this.Visitor(expression);//调用ExpressionVisitor中的Visitor方法;访问表达式目录树的入口}//1.重写ExpressionVisitor中的VisitBinary方法protected override Expression VisitBinary(ExpressionBinary b)//VisitBinary对应ExpressionBinary{if(b.NodeType == ExpressionType.Add){Expression left = this.Visit(b.Left);//递归进入VisitBinary()Expression right = this.Visit(b.Right);return Expression.Subtract(left, right);}return base.VisitBinary(b);}//同理可以重写多个基类中的方法
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


8.async / await 语法糖

async 修饰方法名称的;

主线程遇到await A后就返回了,await A后面的内容由新线程执行;await A的线程遇到await B时又被返回了(await A被放回线程池,表示A活干完了),await B后面的内容被await B执行;总结:线程遇到await A后就返回
程序中要么不用await,要么从头用到尾;

//当程序中没有async时,想用async时;
await Task.CompletedTask();//官方框架推荐
await Task.Delay();
结果:可以增加吞吐量,提升性能;
但是:不是所有的程序都适用async/await;如下

await / async能并发吗?一定能提升性能吗?意义何在?
单个方法内不能并发,线程在遇到await 时就返回了,后续内容由新线程执行,属于串行执行;
不能提升性能,性能会低于同步调用,比如:对于同一个方法,单次处理,是没有性能提升的,只会增加负荷;
意义:1、在多请求并发处理,且资源有限的时候,能增加吞吐量(增加单位时间处理的请求)

举例:一个孩子进食时间为一小时,**1个老师喂4个孩子(await并行)的时候与和一个老师喂一个孩子(普通串行)**进行比较;await并行时,老师在喂第一个孩子的时候,剩下三个孩子自己进食,然后依次喂食,最终花费时间会小于4小时;普通串行时,老师一个一个喂,最终还是花费4小时;

ILSpy 5.x反编译dll文件,查看源码

ILSpy 中存在状态机,用变量_State表示,状态机模式:一个对象根据不同的状态会有不同的行为(对象只有一个,类似于红绿灯)

Task和await的区别
举例:读本地文件;
Task方式–启动10个线程,分别等着读取文件 ,线程一直处于等待状态,cpu一直被消耗;
await方式–实际上看不到线程,调用系统封装的异步API,发起请求,线程就回去了–由硬件自行读取,读完之后发信号,然后线程池再安排线程去处理;
类似例子:还有调用webApi,WCF,远程数据库链接,连接第三方、读缓存;(都值得使用async)
类似于纯CPU计算类型的(不值得使用async,反而浪费线程资源)

9.反射

9.1反射的原理、反射的使用

9.1.1反射的原理

什么是反射?
答:Reflection命名空间,是微软的一个帮助类库,可以读取metadate元数据,可以使用对应metadate元数据中的方法;

高级语言到机器识别过程:C#高级语言 --> 编译器编译 --> DLL/EXE(又包含了metadate元数据(类似于清单,只能看见方法名)、IL(中间语言)) --> CLR/JIT --> 机器码010101

9.1.2反射的使用

IOC中的实现;

//基础类
public class SqlServerHelper : IDBHelper
{public SqlServerHelper(){}public void Query(){//查询内容}
}public Interface IDBHelper()
{public void Query();
}
public static IDBHelper CreateInstance()
{//1.动态加载DLLAssembly assembly = Assembly.Load("dll名称");//LoadFrom()//2.获取类型Type type = assembly.GetType("dll名称.对应的Helper类A");//Helper类A继承IDBHelper//3.创建对象object odbHelper = Activator.CreateInstance(type);//4.类型转换成对应的HelperIDBHelper dbHelper = odbHelper.IDBHelper;//5.调用方法dbHelper.Query();
}

9.1.3反射的好处和局限

为什么要这么做呢?
1.这样可以断开对细节的依赖(不用添加命名空间引用)

2.实现程序可配置:公司来了技术经理,要求更换数据库为Mysql,按照普通方式写的话,需要改代码,重新编译,重新发布等麻烦步骤;通过反射的话,只需要修改appsetting.json中的即可,不需要重新改代码,重新编译等麻烦步骤,实现了程序可配置;(前提两个数据库的Helper类已经存在了,减少了改代码,编译,发布等步骤)

3.增加了程序扩展性(如果公司只有sqlserver和mysqlhelper,没有orcale数据库的helper类,现在又需要使用orcale数据库,我们最终只需要添加新的orcale project + 改配置文件即可;)

4.实现的就是IOC控制反转的核心思想

9.1.3.2 局限

9.1.4封装

9.1.2中的程序看起来需要很多代码,所以我们要进行封装一下就好;

public class SimpleCreateInstance()
{public Static IDBHelper CreateOnstance(){//(1)基本封装代码Assembly assembly = Assembly.Load("dll名称A");//LoadFrom()Type type = assembly.GetType("dll名称A.对应的Helper类A");//这两个步骤可通过配置文件进行优化,如下object odbHelper = Activator.CreateInstance(Type);IDBHelper dbHelper = odbHelper.IDBHelper;return dbHelper;//(2)优化封装代码//core中在appsetting.json通过key value进行配置;//配置如:"dbHelperRefliction":"dll名称A.对应的Helper类A, dll名称A.dll"string TypeName = CustomConfigManager.GetConfig("dbHelperRefliction").Split(',')[0];  //dll名称A.对应的Helper类Astring DllName = CustomConfigManager.GetConfig("dbHelperRefliction").Split(',')[1];  //dll名称AAssembly assembly = Assembly.Load(DllName);//LoadFrom()Type type = assembly.GetType(TypeName);//这两个步骤可通过配置文件进行优化,如下object odbHelper = Activator.CreateInstance(Type);IDBHelper dbHelper = odbHelper.IDBHelper;return dbHelper;}
}
public static main()
{IDBHelper idbHelper = SimpleCreateInstance.CreateInstance();idbHelper.Query();
}

9.2反射在项目的应用

MVC中的实现:
localhost:8080/Home/Index
为什么浏览器访问这个路径,就可以进入到Action中去呢?最终就是调用Action。


{//----------------------------//(1)无参公共方法Console.WriteLine("反射调用普通方法");//1.动态加载dllAssembly assembly = Assembly.LoadForm(@"xxx.dll");//2.获取类型Type type =  assembly.GetType(@"xxx.dll.类名");//3.创建对象object oTest = Activator.CreateInstance(type);//方法如何调用呢?//4.获取方法MethodInfo show1 = type.GetMethod("show1");//show1为自定义的无参方法;//5.利用Invoke去调用方法show1.Inoke(oTest,new object[0]);//Inoke需要传输两个参数,所以我们就创建了一个空的对象;new object[0]写法是新的写法;//结果:成功调用//-----------------------------//(2)带参数的公共方法MethodInfo show2 = type.GetMethod("show2");//show2为自定义的有参方法;show2(int id);show2.Inoke(oTest,new object[]{123});//成功show2.Inoke(oTest,new object[]{"ZiFuChuan"});//失败;注意:在传递参数的时候,一定要注意,必须要和方法的参数类型一致;//-------------------------------//(3)带参数的公共重载方法//show3(int id, string name);//show3(string name, int id);//show3(int id);//MethodInfo show3 = type.GetMethod("show3");// 这种方式是有错误的,因为不知道是哪个具体的方法;MethodInfo show3 = type.GetMethod("show3", new Type[] {typeof(int), typeof(string)});//这样就获取到了show3(int id, string name)方法show3.Inoke(oTest,new object[]{123, "ZiFuChuan"});//成功//---------------------//(4)带参数的**私有**方法//show4为自定义的有参方法;show4(string name);//MethodInfo show4 = type.GetMethod("show4");//因为是private,所以这样获取不到的MethodInfo show4 = type.GetMethod("show4", BindingFlags.NonPublic | BindingFlags.Instance);//传递枚举进去NonPublic,就可以找得到private方法了;show4.Inoke(oTest,new object[]{"ZiFuChuan"});//---------------------//(5)静态方法MethodInfo show5 = type.GetMethod("show5");//4.获取方法show5.Inoke(oTest,new object[]{"ZiFuChuan"});//成功show5.Inoke(null,new object[]{"ZiFuChuan"});//成功。静态方法的调用其实不需要具体的实例,只需要“类型.静态方法名”即可,所以这里不传递实例也是可以的。调用静态方法的基础知识;//---------------------//(6)普通类的泛型方法//show6<T, W, X>(T t, W w, X x)//普通方法调用方式:对象.Show6<int, string, DateTime>(123, "ZiFuChuan", DateTime.Now);//普通方法调用方式:对象.Show6(123, "ZiFuChuan", DateTime.Now);这种方法之所以成功是因为语法糖来确定的;MethodInfo show6 = type.GetMethod("show6");//4.获取泛型方法,成功//show6.Inoke(oTest,new object[]{123, "ZiFuChuan", DateTime.Now});//失败MethodInfo showNew6 = show6.MakeGenericMethod(new Type[]{typeof(int), typeof(string), typeof(DateTime)});//MakeGenericMethod指定类型showNew6.Inoke(oTest,new object[]{123"ZiFuChuan", DateTime.Now});//---------------------//(7)泛型类的泛型方法1//show7<T, W, X>(T t, W w, X x);;public class A<T, W, X>Assembly assembly = Assembly.LoadForm(@"xxx.dll");//这里class为A//Type type =  assembly.GetType(@"xxx.dll.A");//结果:获取不到Type type =  assembly.GetType(@"xxx.dll.A`3");//结果:成功;`3表示泛型,参数有3个;//object oTest = Activator.CreateInstance(type);//失败,因为通过普通方法 A obj = new A();是不允许的;需要指定类中的泛型;Type typeNew = type.MakeGenericType(typeof(int), typeof(string), typeof(DateTime));//MakeGenericType指定类型object oTest = Activator.CreateInstance(typeNew);//成功MethodInfo show7 = typeNew.GetMethod("show7");//成功,因为是基于类的泛型;这里就不需要再次指定类型了show7.Inoke(oTest,new object[]{123"ZiFuChuan", DateTime.Now});//---------------------//(8)泛型类的泛型方法2//show8<T, W, X>(T t, W w, X x);;public class A<T>//+++++++注意这里类的泛型+++++++Assembly assembly = Assembly.LoadForm(@"xxx.dll");//这里class为AType type =  assembly.GetType(@"xxx.dll.A`1");//结果:成功;`1表示泛型,参数有1个;Type typeNew = type.MakeGenericType(typeof(int), typeof(string), typeof(DateTime));//MakeGenericType指定类型object oTest = Activator.CreateInstance(typeNew);//成功MethodInfo show8 = typeNew.GetMethod("show8");//成功的,但是剩下2个泛型类未指定;需要进行指定show8New = show8.MakeGenericMethod(new Type[]{typeof(int), typeof(DateTime)});//MakeGenericMethod指定类型,方法中剩下的泛型按顺序指定;show7.Inoke(oTest,new object[]{"ZiFuChuan", 123, DateTime.Now});//成功}

总:所以实际上在MVC请求网站的时候 ,会一步一步的解析出域名、端口、ControllerName、方法Index;实际上是通过反射的方式定位到具体的位置;

9.3反射封装框架,在线手写ORM框架

9.3.1通过反射操作属性或字段

{///1.普通方式People people = new People(){Id = 123,Name = "zifucahun",Age = 25};Console.WriteLine($"{people.Id}");//取值///2.反射的实现,如下Type type = typeof(People);object oPeople = Activator.CreateInstance(type);//创建实例//赋值foreach(var prop in type.GetProperties){if(prop.Name.Equals("Id")){prop.SetValue(oPeople, 123);//赋值}}//取值foreach(var field in type.GetFields()){Console.WriteLine($"oPeople.{field.Name} = {field.GetValue(oPeople)}");//遍历取值}//反射的好处//1.通过普通方式无论是赋值还是取值都需要需改代码(当增加、删除、更新一个字段时)//2.反射取值的时候,就不需要改代码,但是赋值的还是需要修改的;	}

9.3.2 使用反射在ORM框架的实现


public class main
{SqlServerHelper sqlServerHelper = new SqlServerHelper();//Student 和Teacher 两个Model对应数据库表;Student s1 = sqlServerHelper.Query(1);Teacher t1 = sqlServerHelper.Query(1);
}public class SqlServerHelper
{//ORM,面向对象思想。本质:通过对类的操作,实现对数据库的操作(类与数据库的字段和类型必须一致)Public T Query<T>(int id)  //Public T Query<T>(string sqlstr){//1.数据库连接字符串string conn ="Data Souce=主机名称; Database=数据库名称;User ID=sa;Password=数据库登录密码; MultipleActiveResultSets=True;";//2.准备SQl语句string sql = "";//+++++SQL语句可以拆分外部,灵活性更大;++++Type type = typeof(T);//获取泛型T的类名称;//泛型T类对应数据库表;object oObj = Activator.CreateInstance(type);//创建泛型T类对应的实例oObj //3.连接数据库Using(SqlConnection connection = new SqlConnection(conn)){connection.Open();SqlCommand sqlCommand = new SqlCommend(sql, connection);//将SQL语句连接数据库;SqlDataReader reader = sqlCommand.ExecuteReader();//准备执行数据读取reader.Read();//读取数据//下面使用反射的方式;foreach(var prop in type.GetProperties())//遍历T的所有属性{//给泛型T的实例对象oObj设置属性值,属性值通过从reader索引获取;value = reader[属性名称];prop.SetValue(oObj,reader[prop.Name]);//注意写法}}return (T)oObj;// return oObj as T;//注意这两种写法的区别}//如果只想查询部分字段,可以通过 “特性” 进行过滤;
}

http://www.ppmy.cn/news/864922.html

相关文章

apache 基金会 project 概述

Ambari 是一种基于Web的工具&#xff0c;支持Apache Hadoop集群的供应、管理和监控。Ambari目前已支持大多数Hadoop组件&#xff0c;包括HDFS、MapReduce、Hive、Pig、 Hbase、Zookeper、 Sqoop和Hcatalog等。支持HDFS、MapReduce、Hive、Pig、Hbase、Zookeper、Sqoop和Hcatalo…

Python版day41

343. 整数拆分 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 class Solution:def integerBreak(self, n: int) -> int:# dp[i]分解数字i所得到的最大…

设计模式详解(一):工厂方法——Factory Method

目录导航 工厂方法及其作用工厂方法的好处工厂方法的实现关系图实现步骤 工厂方法的适用场景工厂方法举例 工厂方法及其作用 工厂方法是一种创建型设计模式。所谓创建型设计模式是说针对创建对象方面的设计模式。在面向对象的编程语言里&#xff0c;我们通过对象间的相互协作&…

黄河水中的含沙量有多大?(为什么叫悬河)

在世界上含沙量较大的几条著名河流中&#xff0c;美国的密西西比河每立方米含沙1公斤&#xff0c;埃及的尼罗河是1.62公斤&#xff0c;苏联的阿姆河是2.3公斤&#xff0c;而黄河每立方米水中泥沙的含量竟高达37.6公斤。为它取名黄河&#xff0c;真是再确切不过了。 出路告黄河…

数据读取及预处理方法-缺失值处理、独热编码、重复值处理、异常值检测

一个完整的数据分析流程大致应分为三步&#xff1a;收集数据、处理数据、数据建模预测及可视化。而在实际工作中&#xff0c;前两项内容占据的时间远远超过最后一步。 数据收集 三种方法&#xff1a;数据接口、数据库、数据爬虫 数据读取 在读取数据时&#xff0c;我们最常…

从地图投影折射出的中西方文化差异

从地图投影折射出的中西方文化差异 文章目录 从地图投影折射出的中西方文化差异前言地球的形状路易十四 VS 康熙大帝古代中国 VS 古代西方 地球坐标系地图投影圆柱投影圆锥投影方位角投影 参考文献 前言 这几天&#xff0c;因为项目需要&#xff0c;认真地学习了一遍地图投影&…

课程总结

1.当初你是如何做出选择计算机专业的决定的&#xff1f; 因为这个专业前景好&#xff0c;有前途。 2.对比开篇博客&#xff0c;哪些方面还存在不足&#xff1f; 一开始写的代码复杂&#xff0c;暴力&#xff0c;死板。 3.回忆整个学期&#xff0c;如果重新来过一次&#xff0c;…

走遍美国之纽约

读万卷书&#xff0c;行万里路。 作为个人游记&#xff0c;最近想写一个系列&#xff0c;谈谈在美国游历过的几个地方。同时作为亲历者&#xff0c;也算是一种推荐&#xff0c;供有兴趣到美国旅行的国人之参考&#xff0c;特别是一些必到的地方、必看的东西。 纽约是美国最大…

聊聊soho办公-人们为什么越来越累

soho&#xff0c;即Small Office&#xff0c;Home Office的首字母缩写。 搞互联网的真幸运&#xff0c;可以soho办公&#xff0c;不用担心工作和收入受到影响&#xff0c;然而&#xff0c;这也正是互联网从业者soho之不幸。 因为被剥夺了自由。 上一次soho应该是1万年以前了…

【逻辑与计算理论】从逻辑到计算的转变之路

【逻辑与计算理论】从逻辑到计算的转变之路 总所周知,λ-演算与组合子演算构成的邱奇计算理论与图灵的图灵机模型共同构成了计算机计算理论的支柱。在前面的文章中我们已经讨论过了自动机与图灵机相关理论,在这里我们将进入 λ-演算与组合子 计算理论的相关介绍。对于 λ-演算…

【笔记】行测——常识判断之经济常识总结与归纳(二)

文章目录 一、重要经济组织二、热点经济名词 一、重要经济组织 【笔记】行测——常识判断之经济常识总结与归纳&#xff08;一&#xff09; 二、热点经济名词 名词含义二八定律二八定律又名80/20定律、帕累托法则也叫巴莱特定律、朱伦法则、关键少数法则、不重要多数法则最省…

历史类:四大文明古国

历史类&#xff1a;四大文明古国 古巴比伦两河流域两河文明与古巴比伦文明 古埃及上埃及和下埃及法老胡夫金字塔 古印度种姓制度释迦摩尼 中国长城 四大文明古国&#xff0c;是关于世界四大古代文明的统称。 分别是古巴比伦(位于西亚&#xff0c;今地域属伊拉克)、古埃及(位于西…

数据预处理之缺失值处理

缺失值产生原因 数据集中部分数据的缺失是一件很头疼的事情,不但增大了数据集的不确定性,也影响了算法的执行。缺失值产生的原因主要有以下几点: 1.有些信息暂时无法获取,或获取信息的成本过高 2.信息遗漏,即人为的原因,如收集信息不认真、忘记填写信息等 3.缺失值本…

【笔记】行测——常识判断之地理常识总结与归纳(二)

文章目录 第一章 自然地理第二章 世界地理一、海陆概况&#xff08;一&#xff09;七大洲&#xff08;二&#xff09;七大洲大小&#xff08;三&#xff09;大洲分界线&#xff08;四&#xff09;四大洋&#xff08;五&#xff09;海峡和运河 二、山川湖泊&#xff08;一&#…

4.25学习内容

1.静态变量 不同的类需要对同一个变量进行操作&#xff0c;就需要定义一个静态变量 public class Pool {static public int water 0;//这就是一个静态变量public void outlet() {if(water>2) {water-2;}else {water 0;}}public void inlet() {water 2;}public static vo…

聚苯乙烯PS彩色胶乳微球:红色/蓝色/黑色/绿色胶乳微球介绍和制备方法

聚苯乙烯PS彩色胶乳微球&#xff0c;红色胶乳微球 蓝色胶乳微球 黑色胶乳微球 绿色胶乳微球等多种颜色微球粒径50nm~500nm&#xff0c;和小编一起来看&#xff01; 单分散彩色胶乳微球&#xff08;多种规格尺寸 表面修饰羧基 氨基 环氧基 磺酸基等&#xff09; 【英文名称】co…

《Python编程 从入门到实践》第六章 ——字典习题

6-5 创建一个字典,在其中存储三条大河流及其流经的国家,使用循环为每条河流打印一条消息。 rivers = { 尼罗河 : 埃及, 长江: 中国, 亚马逊 : 巴西, } for river, country in rivers.items(): print ("The " + str(river) + …

时间序列分析Nile案例(基于R)

时间序列分析Nile案例&#xff08;基于R&#xff09; 时间序列分析Nile案例数据预处理 时间序列分析Nile案例 在 R 的 datasets 包中&#xff0c;包含一个 Nile 的数据集&#xff0c;该数据是一个时间序列数据&#xff0c;主要记录了 1971 年-1970 年尼罗河每年的流量&#xf…

我在Blue Nile(蓝色尼罗河)上通过python爬取一百万颗钻石,最终选出心仪的一颗

--------代码在文章最下面---------- 俗话说&#xff1a;钻石恒久远&#xff0c;一颗永流传 先说一下背景&#xff0c;楼主是某小型互联网公司的数据分析师&#xff0c;因为以前有编程的基础&#xff0c;所以略懂一点爬虫相关的技术。由于到了结婚的年龄&#xff0c;所以找到政…

2015年第5本(英文第4本):Death on the Nile尼罗河上的惨案

书名&#xff1a;Death on the Nile 作者&#xff1a; Agatha Christie 单词数&#xff1a;7.9万&#xff08;读完后发现网上还有一个版本&#xff0c;总共2.7万单词&#xff0c;孩子都能读懂&#xff0c;看来是简写版&#xff09; 词汇量&#xff1a;6700 首万词不重复词数&am…