CSharp初体验

入门

初来乍到了解一门新的语言,它可能和熟悉的c/c++有不小差别,整体上需要首先了解下语法文件的整体结构。例如,源文件整体结构如何。

乍看CSharp源文件(compile unit)的结构,官网主要是通过文字描述的整体结构,而下面的形式化语法,描述也不太符合自定向下这种类型的语法结构描述方法,这样对于新手来了解这种语言的整体结构来说就有些困难。

好在有一个开源的dotgnu项目,该项目的官方文档中显示,项目已经在2012年正式废弃(可能更早已经没有更新了)。从工程的语法描述文件来看,它还没有涉及到lambda表达式这种重要语法功能的支持,不知道是因为项目启动时暂时没有支持,或者是启动时CSharp还没有这种语法功能。

As of December 2012, the DotGNU project has been decommissioned, until and unless a substantial new volunteer effort arises. The exception is the libjit component, which is now a separate libjit package.

dotgnu

尽管该项目比较久远,但是它的语法描述是通过经典的yacc语法描述,这样对于理解整体结构时最为直观的。其中对于整体结构的描述大致如下。从这个描述来看,整个源文件的结构顶层只能包含using、namespace、class、enum、struct、module、interface、delegate这些声明。

///@file: DotGnu\pnet\cscc\csharp\cs_grammar.y
/*
 * Outer level of the C# input file.
 */

CompilationUnit
	: /* empty */	{
				/* The input file is empty */
				CCTypedWarning("-empty-input",
							   "file contains no declarations");
				ResetState();
			}
	| OuterDeclarationsRecoverable		{
				/* Check for empty input and finalize the parse */
				if(!HaveDecls)
				{
					CCTypedWarning("-empty-input",
								   "file contains no declarations");
				}
				ResetState();
			}
	| OuterDeclarationsRecoverable NonOptAttributes	{
				/* A file that contains declarations and assembly attributes */
				if($2)
				{
					InitGlobalNamespace();
					CCPluginAddStandaloneAttrs
						(ILNode_StandaloneAttr_create
							((ILNode*)CurrNamespaceNode, $2));
				}
				ResetState();
			}
	| NonOptAttributes	{
				/* A file that contains only assembly attributes */
				if($1)
				{
					InitGlobalNamespace();
					CCPluginAddStandaloneAttrs
						(ILNode_StandaloneAttr_create
							((ILNode*)CurrNamespaceNode, $1));
				}
				ResetState();
			}
	;

/*
 * Note: strictly speaking, declarations should be ordered so
 * that using declarations always come before namespace members.
 * We have relaxed this to make error recovery easier.
 */
OuterDeclarations
	: OuterDeclaration
	| OuterDeclarations OuterDeclaration
	;

OuterDeclaration
	: UsingDirective
	| NamespaceMemberDeclaration
	| error			{
				/*
				 * This production recovers from errors at the outer level
				 * by skipping invalid tokens until a namespace, using,
				 * type declaration, or attribute, is encountered.
				 */
			#ifdef YYEOF
				while(yychar != YYEOF)
			#else
				while(yychar >= 0)
			#endif
				{
					if(yychar == NAMESPACE || yychar == USING ||
					   yychar == PUBLIC || yychar == INTERNAL ||
					   yychar == UNSAFE || yychar == SEALED ||
					   yychar == ABSTRACT || yychar == CLASS ||
					   yychar == STRUCT || yychar == DELEGATE ||
					   yychar == ENUM || yychar == INTERFACE ||
					   yychar == '[')
					{
						/* This token starts a new outer-level declaration */
						break;
					}
					else if(yychar == '}' && CurrNamespace.len != 0)
					{
						/* Probably the end of the enclosing namespace */
						break;
					}
					else if(yychar == ';')
					{
						/* Probably the end of an outer-level declaration,
						   so restart the parser on the next token */
						yychar = YYLEX;
						break;
					}
					yychar = YYLEX;
				}
			#ifdef YYEOF
				if(yychar != YYEOF)
			#else
				if(yychar >= 0)
			#endif
				{
					yyerrok;
				}
				NestingLevel = 0;
			}
	;
///....
OptNamespaceMemberDeclarations
	: /* empty */
	| OuterDeclarations
	;

NamespaceMemberDeclaration
	: NamespaceDeclaration
	| TypeDeclaration			{ CCPluginAddTopLevel($1); }
	;

TypeDeclaration
	: ClassDeclaration			{ $$ = $1; }
	| ModuleDeclaration			{ $$ = $1; }
	| StructDeclaration			{ $$ = $1; }
	| InterfaceDeclaration		{ $$ = $1; }
	| EnumDeclaration			{ $$ = $1; }
	| DelegateDeclaration		{ $$ = $1; }
	;

roslyn

微软官方开源了CSharp的实现,所以最标准的解释应该是来自微软官方代码。遗憾的是这个工程是使用CSharp开发的,所以项目内对于语法的解析也不是通过yacc文件描述,而是手工实现的一个编译器解析。猜测代码应该位于

///@file: roslyn\src\Compilers\CSharp\Portable\Parser

        internal CompilationUnitSyntax ParseCompilationUnitCore()
        {
            SyntaxToken? tmp = null;
            SyntaxListBuilder? initialBadNodes = null;
            var body = new NamespaceBodyBuilder(_pool);
            try
            {
                this.ParseNamespaceBody(ref tmp, ref body, ref initialBadNodes, SyntaxKind.CompilationUnit);

                var eof = this.EatToken(SyntaxKind.EndOfFileToken);
                var result = _syntaxFactory.CompilationUnit(body.Externs, body.Usings, body.Attributes, body.Members, eof);

                if (initialBadNodes != null)
                {
                    // attach initial bad nodes as leading trivia on first token
                    result = AddLeadingSkippedSyntax(result, initialBadNodes.ToListNode());
                    _pool.Free(initialBadNodes);
                }

                return result;
            }
            finally
            {
                body.Free(_pool);
            }
        }
            private void ParseNamespaceBody(
            [NotNullIfNotNull(nameof(openBraceOrSemicolon))] ref SyntaxToken? openBraceOrSemicolon,
            ref NamespaceBodyBuilder body,
            ref SyntaxListBuilder? initialBadNodes,
            SyntaxKind parentKind)
        {
            // "top-level" expressions and statements should never occur inside an asynchronous context
            Debug.Assert(!IsInAsync);

            bool isGlobal = openBraceOrSemicolon == null;

            var saveTerm = _termState;
            _termState |= TerminatorState.IsNamespaceMemberStartOrStop;
            NamespaceParts seen = NamespaceParts.None;
            var pendingIncompleteMembers = _pool.Allocate<MemberDeclarationSyntax>();
            bool reportUnexpectedToken = true;

            try
            {
                while (true)
                {
                    switch (this.CurrentToken.Kind)
                    {
                        case SyntaxKind.NamespaceKeyword:
                            // incomplete members must be processed before we add any nodes to the body:
                            AddIncompleteMembers(ref pendingIncompleteMembers, ref body);

                            var attributeLists = _pool.Allocate<AttributeListSyntax>();
                            var modifiers = _pool.Allocate();

                            body.Members.Add(adjustStateAndReportStatementOutOfOrder(ref seen, this.ParseNamespaceDeclaration(attributeLists, modifiers)));

                            _pool.Free(attributeLists);
                            _pool.Free(modifiers);

                            reportUnexpectedToken = true;
                            break;

                        case SyntaxKind.CloseBraceToken:
                            // A very common user error is to type an additional } 
                            // somewhere in the file.  This will cause us to stop parsing
                            // the root (global) namespace too early and will make the 
                            // rest of the file unparseable and unusable by intellisense.
                            // We detect that case here and we skip the close curly and
                            // continue parsing as if we did not see the }
                            if (isGlobal)
                            {
                                // incomplete members must be processed before we add any nodes to the body:
                                ReduceIncompleteMembers(ref pendingIncompleteMembers, ref openBraceOrSemicolon, ref body, ref initialBadNodes);

                                var token = this.EatToken();
                                token = this.AddError(token,
                                    IsScript ? ErrorCode.ERR_GlobalDefinitionOrStatementExpected : ErrorCode.ERR_EOFExpected);

                                this.AddSkippedNamespaceText(ref openBraceOrSemicolon, ref body, ref initialBadNodes, token);
                                reportUnexpectedToken = true;
                                break;
                            }
                            else
                            {
                                // This token marks the end of a namespace body
                                return;
                            }

                        case SyntaxKind.EndOfFileToken:
                            // This token marks the end of a namespace body
                            return;

                        case SyntaxKind.ExternKeyword:
                            if (isGlobal && !ScanExternAliasDirective())
                            {
                                // extern member or a local function
                                goto default;
                            }
                            else
                            {
                                // incomplete members must be processed before we add any nodes to the body:
                                ReduceIncompleteMembers(ref pendingIncompleteMembers, ref openBraceOrSemicolon, ref body, ref initialBadNodes);

                                var @extern = ParseExternAliasDirective();
                                if (seen > NamespaceParts.ExternAliases)
                                {
                                    @extern = this.AddErrorToFirstToken(@extern, ErrorCode.ERR_ExternAfterElements);
                                    this.AddSkippedNamespaceText(ref openBraceOrSemicolon, ref body, ref initialBadNodes, @extern);
                                }
                                else
                                {
                                    body.Externs.Add(@extern);
                                    seen = NamespaceParts.ExternAliases;
                                }

                                reportUnexpectedToken = true;
                                break;
                            }

                        case SyntaxKind.UsingKeyword:
                            if (isGlobal && (this.PeekToken(1).Kind == SyntaxKind.OpenParenToken || (!IsScript && IsPossibleTopLevelUsingLocalDeclarationStatement())))
                            {
                                // Top-level using statement or using local declaration
                                goto default;
                            }
                            else
                            {
                                parseUsingDirective(ref openBraceOrSemicolon, ref body, ref initialBadNodes, ref seen, ref pendingIncompleteMembers);
                            }

                            reportUnexpectedToken = true;
                            break;

                        case SyntaxKind.IdentifierToken:
                            if (this.CurrentToken.ContextualKind != SyntaxKind.GlobalKeyword || this.PeekToken(1).Kind != SyntaxKind.UsingKeyword)
                            {
                                goto default;
                            }
                            else
                            {
                                parseUsingDirective(ref openBraceOrSemicolon, ref body, ref initialBadNodes, ref seen, ref pendingIncompleteMembers);
                            }

                            reportUnexpectedToken = true;
                            break;

                        case SyntaxKind.OpenBracketToken:
                            if (this.IsPossibleGlobalAttributeDeclaration())
                            {
                                // incomplete members must be processed before we add any nodes to the body:
                                ReduceIncompleteMembers(ref pendingIncompleteMembers, ref openBraceOrSemicolon, ref body, ref initialBadNodes);

                                var attribute = this.ParseAttributeDeclaration();
                                if (!isGlobal || seen > NamespaceParts.GlobalAttributes)
                                {
                                    RoslynDebug.Assert(attribute.Target != null, "Must have a target as IsPossibleGlobalAttributeDeclaration checks for that");
                                    attribute = this.AddError(attribute, attribute.Target.Identifier, ErrorCode.ERR_GlobalAttributesNotFirst);
                                    this.AddSkippedNamespaceText(ref openBraceOrSemicolon, ref body, ref initialBadNodes, attribute);
                                }
                                else
                                {
                                    body.Attributes.Add(attribute);
                                    seen = NamespaceParts.GlobalAttributes;
                                }

                                reportUnexpectedToken = true;
                                break;
                            }

                            goto default;

                        default:
                            var memberOrStatement = isGlobal ? this.ParseMemberDeclarationOrStatement(parentKind) : this.ParseMemberDeclaration(parentKind);
                            if (memberOrStatement == null)
                            {
                                // incomplete members must be processed before we add any nodes to the body:
                                ReduceIncompleteMembers(ref pendingIncompleteMembers, ref openBraceOrSemicolon, ref body, ref initialBadNodes);

                                // eat one token and try to parse declaration or statement again:
                                var skippedToken = EatToken();
                                if (reportUnexpectedToken && !skippedToken.ContainsDiagnostics)
                                {
                                    skippedToken = this.AddError(skippedToken,
                                        IsScript ? ErrorCode.ERR_GlobalDefinitionOrStatementExpected : ErrorCode.ERR_EOFExpected);

                                    // do not report the error multiple times for subsequent tokens:
                                    reportUnexpectedToken = false;
                                }

                                this.AddSkippedNamespaceText(ref openBraceOrSemicolon, ref body, ref initialBadNodes, skippedToken);
                            }
                            else if (memberOrStatement.Kind == SyntaxKind.IncompleteMember && seen < NamespaceParts.MembersAndStatements)
                            {
                                pendingIncompleteMembers.Add(memberOrStatement);
                                reportUnexpectedToken = true;
                            }
                            else
                            {
                                // incomplete members must be processed before we add any nodes to the body:
                                AddIncompleteMembers(ref pendingIncompleteMembers, ref body);

                                body.Members.Add(adjustStateAndReportStatementOutOfOrder(ref seen, memberOrStatement));
                                reportUnexpectedToken = true;
                            }
                            break;
                    }
                }
            }
            finally
            {
                _termState = saveTerm;

                // adds pending incomplete nodes:
                AddIncompleteMembers(ref pendingIncompleteMembers, ref body);
                _pool.Free(pendingIncompleteMembers);
            }

            MemberDeclarationSyntax adjustStateAndReportStatementOutOfOrder(ref NamespaceParts seen, MemberDeclarationSyntax memberOrStatement)
            {
                switch (memberOrStatement.Kind)
                {
                    case SyntaxKind.GlobalStatement:
                        if (seen < NamespaceParts.MembersAndStatements)
                        {
                            seen = NamespaceParts.MembersAndStatements;
                        }
                        else if (seen == NamespaceParts.TypesAndNamespaces)
                        {
                            seen = NamespaceParts.TopLevelStatementsAfterTypesAndNamespaces;

                            if (!IsScript)
                            {
                                memberOrStatement = this.AddError(memberOrStatement, ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType);
                            }
                        }

                        break;

                    case SyntaxKind.NamespaceDeclaration:
                    case SyntaxKind.FileScopedNamespaceDeclaration:
                    case SyntaxKind.EnumDeclaration:
                    case SyntaxKind.StructDeclaration:
                    case SyntaxKind.ClassDeclaration:
                    case SyntaxKind.InterfaceDeclaration:
                    case SyntaxKind.DelegateDeclaration:
                    case SyntaxKind.RecordDeclaration:
                    case SyntaxKind.RecordStructDeclaration:
                        if (seen < NamespaceParts.TypesAndNamespaces)
                        {
                            seen = NamespaceParts.TypesAndNamespaces;
                        }
                        break;

                    default:
                        if (seen < NamespaceParts.MembersAndStatements)
                        {
                            seen = NamespaceParts.MembersAndStatements;
                        }
                        break;
                }

                return memberOrStatement;
            }

            void parseUsingDirective(
                ref SyntaxToken? openBrace,
                ref NamespaceBodyBuilder body,
                ref SyntaxListBuilder? initialBadNodes,
                ref NamespaceParts seen,
                ref SyntaxListBuilder<MemberDeclarationSyntax> pendingIncompleteMembers)
            {
                // incomplete members must be processed before we add any nodes to the body:
                ReduceIncompleteMembers(ref pendingIncompleteMembers, ref openBrace, ref body, ref initialBadNodes);

                var @using = this.ParseUsingDirective();
                if (seen > NamespaceParts.Usings)
                {
                    @using = this.AddError(@using, ErrorCode.ERR_UsingAfterElements);
                    this.AddSkippedNamespaceText(ref openBrace, ref body, ref initialBadNodes, @using);
                }
                else
                {
                    body.Usings.Add(@using);
                    seen = NamespaceParts.Usings;
                }
            }
        }

乌龙

因为这个这种手撕的编译器代码看起来过于晦涩,又回头看了下CSharp的官方语言描述,其中是有编译单元入口描述的,只是隐藏的位置比较深,所以刚开始没看到([流汗]),这个最顶层的语法结构就是compilation_unit,从这个依次向下可以看到对于该结构的逐层描述和细化。从这个语法描述结构来看,最顶层的结构的确只能宝库using开始的结构,然后就是namespace,以及type_declaration。

// Source: §14.2 Compilation units
compilation_unit
    : extern_alias_directive* using_directive* global_attributes?
      namespace_member_declaration*
    ;
    
// Source: §22.3 Attribute specification
global_attributes
    : global_attribute_section+
    ;

// Source: §14.6 Namespace member declarations
namespace_member_declaration
    : namespace_declaration
    | type_declaration
    ;

// Source: §14.7 Type declarations
type_declaration
    : class_declaration
    | struct_declaration
    | interface_declaration
    | enum_declaration
    | delegate_declaration
    ;
// Source: §14.3 Namespace declarations
namespace_declaration
    : 'namespace' qualified_identifier namespace_body ';'?
    ;
    
global_attribute_section
    : '[' global_attribute_target_specifier attribute_list ']'
    | '[' global_attribute_target_specifier attribute_list ',' ']'
    ;
    

lambda表达式

在众多表达式中,这种lambda是一种比较顺手的语法结构,经在很多项目中出镜率还是很高的,所以还是要看下这个语法。在这个语法描述中,可以看到,关键的是"=>"这个语法结构,在这个结构之前,可以使用括弧(explicit_anonymous_function_signature),也可以不使用(implicit_anonymous_function_signature)。这种语法其实很难使用yacc语法描述,因为它对上下文的依赖非常强。

// Source: §12.19.1 General
lambda_expression
    : 'async'? anonymous_function_signature '=>' anonymous_function_body
    ;
anonymous_function_signature
    : explicit_anonymous_function_signature
    | implicit_anonymous_function_signature
    ;

explicit_anonymous_function_signature
    : '(' explicit_anonymous_function_parameter_list? ')'
    ;
implicit_anonymous_function_signature
    : '(' implicit_anonymous_function_parameter_list? ')'
    | implicit_anonymous_function_parameter
    ;

implicit_anonymous_function_parameter_list
    : implicit_anonymous_function_parameter
      (',' implicit_anonymous_function_parameter)*
    ;

implicit_anonymous_function_parameter
    : identifier
    ;
    

其它=>

搜索语法中的这个'=>',可以发现除了lambda表达式之外,还有其他的场景使用,例如local_function_body。同样是这种语法结构,那么如何区域分是lambda表达式还是local_function呢?其实看下语法的上下文就可以看到,localfunction中'=>'前面是需要有类型(return_type)声明,而lambda表达式中的implicit_anonymous_function_parameter是作为expression来出现的,而顾名思义,expression表达式的前面是不可能出现type这种类型前缀引导的。

这里再次看到,CSharp这种语言是很难通过yacc这种通用的语法工具来描述。

// Source: §13.6.4 Local function declarations
local_function_declaration
    : local_function_header local_function_body
    ;

local_function_header
    : local_function_modifier* return_type identifier type_parameter_list?
        ( formal_parameter_list? ) type_parameter_constraints_clause*
    ;
local_function_modifier
    : 'async'
    | 'unsafe'
    ;

local_function_body
    : block
    | '=>' null_conditional_invocation_expression ';'
    | '=>' expression ';'
    ;

推论

全局变量

一个直接的推论是:不存在类似于C/C++中“全局变量”的概念。

main函数

由于不存在全局变量或者函数,所以也不存在类似于C/C++的全局main函数入口,所以整个应用(application)的入口只能位于某个class(不特定)内部,语言规定作为必须声明为static public类型。

what if no namespace

从语法上看,namespace并不是必须的,如果没有把声明放在namespace中,那么和C++一样,声明会放在全局globalnamespace中。

栗子

但是,按照语法规范写的代码并不代表就是合法的。例如下面根据语法规范写的代码,大部分都是错误:-(——编程好难啊……

using System;

//命名空间不能直接包含字段或方法之类的成员
int leela = 1;

namespace harry
{
	class harry
	{
		public static int fry(int x, int y)
		{
			int localfunc() => x + y;
			//只有 assignment、call、increment、decrement 和 new 对象表达式可用作语句
			z => z + 1;
			//error CS0149: 应输入方法名称
			int dd = ((int a) => a + 1)(1);
			return localfunc();
		}
		public static int Main()
		{
			return fry(3, 7);
		}
	};
}


namespace tsecer
{
	//命名空间不能直接包含字段或方法之类的成员
	void tsecer(){}
}
本文转载于网络 如有侵权请联系删除

相关文章

  • ping的原理

    一、什么是PING DOS命令,一般用于检测网络通与不通,也叫时延,其值越大,速度越慢PING(PacketInternetGrope),因特网包探索器,用于测试网络连接量的程序。Ping发送一个ICMP回声请求消息给目的地并报告是否收到所希望的ICMP回声应答。它是用来检查网络是否通畅或者网络连接速度的命令。作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:网络上的机器都有唯一确定的IP地址,我们给目标IP地址发送一个数据包,对方就要返回一个同样大小的数据包,根据返回的数据包我们可以确定目标主机的存在,可以初步判断目标主机的操作系统等。Ping是Windows系列自带的一个可执行命令。利用它可以检查网络是否能够连通,用好它可以很好地帮助我们分析判定网络故障。应用格式:PingIP地址。该命令还可以加许多参数使用,具体是键入Ping按回车即可看到详细说明。ping指的是端对端连通,通常用来作为可用性的检查,但是某些病毒木马会强行大量远程执行ping命令抢占你的网络资源,导致系统变慢,网速变慢。严禁ping入侵作为大多数防火墙的一

  • dequalize滤波

    importcv2 fromskimageimportdata,color importmatplotlib.pyplotasplt fromskimage.morphologyimportdisk importskimage.filters.rankassfr img=cv2.imread('C:/Users/xpp/Desktop/Lena.png')#读取图像 cv2.imshow('original',img) grayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) dst=sfr.equalize(grayImage,disk(5))#半径为5的圆形滤波器 cv2.imshow("result",dst) cv2.waitKey(0) cv2.destroyAllWindows()复制算法:dequalize滤波是均衡化滤波,利用局部直方图对图像进行均衡化滤波。直方图对图像进行均衡化滤波从本质上是一种归一化算法,将目前灰度区间较窄的范围通过一种非线性的方式在整个像素可视空间重映射

  • 【Java】 NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException、ArrayIndexOutOfBoundsE

    今天工作中,临时Fix一个bug,一看日志“java.lang.ClassCastException:null”相当懵逼,没有详细堆栈信息,这咋整。虽然根据上下文可以推测问题代码的大致位置,但不敢拍板啊。只好google找一下,在Stackoverflow上果然有解决办法【解决方法】 在java启动命令中添加“-XX:-OmitStackTraceInFastThrow”即可输出详细堆栈信息——亲测可用。【问题原因】JVM(HotSpotJVM)进行了优化。当第一次发生异常(通常为NullPointerException)时,将打印完整的堆栈跟踪,并且JVM会记住堆栈跟踪(或者可能只是代码的位置)。当该异常经常发生时,将不再打印堆栈跟踪,这既可以实现更好的性能,【CoederBaby】又不会使相同的堆栈跟踪充满日志【进一步分析】参看JVM源码(参见附录2),可见这个优化同时试用于以下异常:NullPointerExceptionArrayIndexOutOfBoundsExceptionClassCastExceptionArrayIndexOutOfBoundsExceptionAr

  • 记一次饿了么大前端技术交流会

    序言上个周六,我有幸去「饿了么」总部参加了一场大前端技术交流会,感受还是有点的,本应该当天晚上就提笔写下这篇文章,无奈周五晚上写完上一篇文章直到凌晨两点才睡觉,第二天又早起奔波了一个小时去参加了一整天的交流会,晚上回来的时候已经疲惫不堪,而周日又在自己捣鼓移动端web适配的问题,于是拖到了今天。 主讲内容交流会总共由「饿了么」的大前端工程师分享了七个主题,下面我将按照顺序一一回顾并介绍。1、PWA在饿了么的实践PWA是什么?ProgressiveWebApps,即渐进式web应用。自古以来,app应用一直分为两大阵营:webapp、nativeapp。webapp构建于浏览器之上,而由于浏览器统一标准的存在和发展,webapp具有天然的跨平台优势(不论你是用的传统windows或macOS的pc机,还是android或iOS系统的手机,又或者是iPad或其它各种终端,只要有浏览器,同一个webapp就可以运行),当然浏览器也是运行在这些不同的系统中,适配的问题其实是交给浏览器自身解决了,而至于nativeapp,没有浏览器的依托,直接运行于原生系统中,所以对于android或iOS系统

  • 单线程Redis性能为何如此之高?

    实际项目开发中现在无法逃避的一个问题就是缓存问题,而缓存问题也是面试必问知识点之一,如果面试官好一点可能会简单的问你二八定律或者热数据和冷数据,但是如果问的深入一点可能就会问到缓存更新、降级、预热、雪崩、穿透等问题,而这些问题可能会拦下大部分平时不怎么关注缓存的朋友,这些问题实际上都和缓存服务器息息相关,我们日常中经常使用的缓存服务器一般有两种:Redis和Memcached。本篇开始正式进入Redis系列文章,本篇主要讲讲Redis使用单线程为何速度还能如此之快?既然谈到缓存服务器有两种,那我们为何要选择Redis呢?Redis与Memcached两者之间有何区别呢? Redis和Memcached的区别Redis支持常见数据类型:Redis不仅仅支持简单的key/value类型的数据,同时还提供string(字符串)、list(链表)、set(集合)、zset(有序集合)和hash(哈希类型)等数据结构的存储。而Memcache只支持简单的数据类型String。Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部

  • LightOj_1265 Island of Survival

    题目链接题意:  在孤岛生存,孤岛上有t头老虎,d头鹿,每天会出现随机出现两只生物(包括你自己),如果出现了一只老虎,那么你将被吃掉,如果两只老虎,则两只老虎会同归于尽,其他情况你都将生存下来。  当孤岛上没有老虎时,就视为你生存成功。  问你生存成功的最大概率。思路:  仔细想一想,生存下来其实只和老虎有关,因为你遇上其他情况,你都会存活下来。  就相当于是一个0-1分布,要么活下来,要么被吃掉。  如果t只老虎是一个奇数,那么必然存活失败,因为老虎的消耗是成对的,你要存活下来最基本的条件就是所有的老虎都同归于尽了,或者没有老虎,否则你总会有一天遇见老虎。  如果t只老虎是一个偶数,那么不一定存活成功。  因为每天都会出现两只生物,那么我们计算t只老虎同归于尽的最大概率。  每天随机出现两只生物,所有的情况数:t*(t+1)(因为鹿与存活与否无关),两只老虎遇见的情况数:t*(t-1)  概率P=t*(t-1)/(t*(t+1))=(t-1)/(t+1)代码:1#include<cmath> 2#include<cstdio> 3#include<cst

  • 如何使用Nvidia Jetson Nano构建网络视频录像机

    DavidCardinal是一名专业摄影师和技术专家,他有十年的数码旅行和自然摄影师的经验,并在高科技领域具备20多年软件开发经验。今天,他要来介绍,如何使用NvidiaJetsonNano构建网络视频录像机。在我们关于家庭视频监控系统的文章更新的过程中,我买了一台Nvidia的新JetsonNanos。在玩这个99美元的电路板并用它来使用各种相机进行物体识别时,突然想到这对于小型网络视频录像机(NVR)NAS设备来说将是一个非常有趣的起点。它耗电量很小,便于携带。此外,集成GPU比大多数大型NAS设备具有更多的AI容量,Nano预装了大量的AI工具。因此,对于那些想要玩各种物件识别的人来说,这是理想的。第一步:配置你的NanoNvidia配置Nano非常容易。您只需要一张microSD卡和一台用于刷新L4T(LinuxForTegra)图像的计算机。从技术上讲,你只需要16GB,但系统占用了大部分,所以我使用了64GB的高速卡。一旦你连接了键盘,鼠标和显示器,你需要做的就是插入一个微型USB电源,你将运行Ubuntu18.04。为您预先安装了各种AI工具和演示应用程序。第二步:连接你

  • 利用人性弱点的互联网产品(一)贪婪

    毋容置疑,“贪婪是推动销售的中坚力量”。其实贪婪有个比较俗的名叫做贪便宜。三年前是团购、点购、秒杀、抽奖最疯狂的时候。而现在百团大战、千团大战都已经成过去式,团购领域的竞争基本已经稳定下来,日常生活中团购电影和团购饭馆也已经成为习惯。至于点购、逆向团购、秒杀已经基本成过去时了,抽奖也趋于一种正常稳定的营销手段,没有了之前那种充满狂躁的转发。那么这三年又有哪些利用人性贪婪的天性呢。存储空间最近网盘容量又“竞赛”了,在百度连BUG带营销的“2毛100GB容量一年”不久之后,A轮融资成功的金山快盘给每位用户增加100GB永久免费空间,之后深知普通用户心理的的360也开始赠送用户360GB永久免费空间的活动。就这样,微博上“欢天喜地”的转发分享,几天前还处于5GB-10GB之间的网盘容量瞬间翻几番到了100GB/400GB。可是,高达几百GB的网盘普通用户用得完吗?肯定是用不完的。微软将SkyDrive新用户免费空间容量由25GB降至7GB时,曾做过调查(ViaLiveSina),99.94%的网盘用户只使用了7GB以下的容量。那既然用不完用户为什么还要参加活动呢?因为用户贪。网盘不仅仅是看容

  • react面试应该准备哪些题目

    可以使用TypeScript写React应用吗?怎么操作?(1)如果还未创建CreateReactApp项目直接创建一个具有typescript的CreateReactApp项目:npxcreate-react-appdemo--typescript复制(2)如果已经创建了CreateReactApp项目,需要将typescript引入到已有项目中通过命令将typescript引入项目:npminstall--savetypescript@types/node@types/react@types/react-dom@types/jest复制将项目中任何后缀名为‘.js’的JavaScript文件重命名为TypeScript文件即后缀名为‘.tsx’(例如src/index.js重命名为src/index.tsx)在ReactNative中,如何解决adbdevices找不到连接设备的问题?在使用Genymotion时,首先需要在SDK的platform-tools中加入环境变量,然后在Genymotion中单击Setting,选择ADB选项卡,单击UsecustomAndroidSDK

  • 240. 搜索二维矩阵 II

    编写一个高效的算法来搜索mxn矩阵matrix中的一个目标值target。该矩阵具有以下特性:每行的元素从左到右升序排列。每列的元素从上到下升序排列。示例:现有矩阵matrix如下: [ [1,4,7,11,15], [2,5,8,12,19], [3,6,9,16,22], [10,13,14,17,24], [18,21,23,26,30] ] 给定target=5,返回true。 给定target=20,返回false。复制解:思路:我们仔细的观察矩阵,可以发现,从右上角的数字开始,前面的数字比其小,下面的数字比其大,复合使用二分的思路,只是需要做出一些变形;我们从右上角开始搜索,如果当前值和目标值匹配,那就算是找到了,如果大于目标值,自然要去找更小的,即左移,如果小于目标值,那就去找更大的,即下移。classSolution{ publicbooleansearchMatrix(int[][]matrix,inttarget){ introwLen=matrix.length; if(rowLen==0){ returnfalse; } intcolLen=matrix[0

  • 算法与数据结构学习笔记(目录)

    设立本专栏的初衷在于,我意识到我学习过的很多算法,一段时间不使用就会被我遗忘,于是决定把学习这些算法的过程记录下来,也同时分享给其他有需要的人。 本专栏默认读者会使用基本的C++语言且掌握基本的贪心、搜索、动态规划思想(部分文章也会补充\(Python\)和\(Java\)代码) 当前文章记录数:90+16 方括号里的编号表示笔记中用到的前置算法(并不意味着该算法必须用到)。分类仅作参考,不一定准确。需要说明的是,因为作者的主攻题型具有偏向性和文章发布顺序问题,所以各种类型的笔记数量和编号很可能不平衡。 PS:专栏格式参考了Pecco学长,专栏内容来自很多人的支持,十分感谢! 关于算法模板(C++):Here 学习(复习)笔记:Here 感谢OIwiki社区的帮助! 如果文章存在阅读密码可以私聊获取 搜索和动态规划 动态规划在ACM/OI中的占比非常大。其变化众多,并没有普适性的方法,更多还需要靠实际练习来积累经验和技巧。 资源 AtCoderEducationalDPContest,个人题解 KB基础DP练习 动态规划系列 算法学习笔记(0):动态规划基础

  • mongodb.副本集配置方法(使用keyfile认证部署)

    前提条件:  -已安装MongoDB, 版本以3.6为例  -系统: Debian9  - 建议做副本集的话, 以3台以上为宜, 本文以1台主机2个服务为例   1.创建数据存放的目录, 并授权 sudomkdir/data/db/mongodb-clus/repl1-p&&sudochownmongodb:mongodb/data/db/mongodb-clus/repl1 sudomkdir/data/db/mongodb-clus/repl2-p&&sudochownmongodb:mongodb/data/db/mongodb-clus/repl2复制 2.生成keyfile 这个keyfile生成后, 拷贝到全部副本机器上使用 sudoopensslrand-base64741>>/data/db/mongodb.key sudochownmongodb:mongodb/data/db/mongodb.key sud

  • 从 《郭峰君在物理学上做出的重大贡献》 想到

    @平阳睡狮郭峰君 在 《郭峰君在物理学上做出的重大贡献》     https://tieba.baidu.com/p/1698469972   1楼 提出    “ 一是彻底切断洛变通往伽变的道路,从而使狭义相对论成为空中楼阁。二是将洛变改写为郭变,从而使洛变丧失时空变换的物理学意义。三是证明纯纵向的光多普勒效应和声多普勒效应都服从爱因斯坦给出的关系式,从而使狭义相对论被彻底摧毁。 ”   这些纲领(贡献) 富有价值,   但  @平阳睡狮郭峰君  对此的 数学和物理 推导过程是否正确,  值得大家推敲和研究论证 。  

  • 8.22知识周总结

    基础知识 zookeeper select、epoll适用场景各自优缺点 缓存优化常见的问题:缓存雪崩、缓存穿透、缓存击穿 前缀索引 数据库如何实现事务的四大特性? 数据库大目录知识梳理,基础中的基础 c++线程池原理 进程线程协程 redis 线程安全基础中的基础 内存管理相关的坑csapp 智能指针 mongoDB分布式集群架构 DNS使用了什么协议 c++stl迭代器失效问题 当我们聊到内存管理,我们可以聊什么? os中的内存管理模型:图解系统内存管理章节 csapp-c程序中常见的内存错误 csapp虚拟内存管理机制。 页面置换算法。 动态内存分配csapp 动态表(hash/vector),扩容/摊还分析。vector扩容,vs2015以1.5倍扩容,GCC以2倍扩容 c++自身的内存管理 缓存优化常见的问题:缓存雪崩、缓存穿透、缓存击穿 c++编程过程遇到的常见内存问题以及解决方法 常见问题汇总 动态申请内存中的内存泄漏: 申请/释放 工具排查 对象计数 爆栈,递归调用。解决方法? 递归改迭代 剪枝 通常是逻辑错误,return的出口没有设计好 数组访

  • Win10系统自定义应用默认安装位置

    1、打开注册表编辑器,方法是:打开开始菜单,左键单击运行,出现运行对话框后,输入regedit。     2、找到注册表项\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion    3、在右侧你可以找到数值名称为ProgramFilesDir和ProgramFilesDir(x86)的项目,里面的默认数值数据为“C:\ProgramFiles”和“C:\ProgramFiles(x86)”,将这个值修改为你所需要设定的路径,比如“D:\all-install”,然后确定,退出注册表编辑器。     更改应用安装位置后,只有新应用会被安装到新位置,已安装应用不会被自动转移。  

  • 如何进行竞品分析

    一、使用它 二、分析产品功能背后的需求 三、分析需求面向的用户 四、分析它的商业模式 五、分析产品的战略定位 六、分析产品的功能交互 七、了解产品的视觉设计 八、了解产品的运营推广

  • Nginx打印json日志

    1.修改配置,在http{}中添加 log_formataccess_json'{"@timestamp":"$time_iso8601",' '"host":"$server_addr",' '"clientip":"$remote_addr",' '"size":$body_bytes_sent,' '"responsetime":$request_time,' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"url":"$uri",' '"domain":"$host",' '"xff":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"status":"$status"}'; access_log/var/log/nginx/access.logaccess_json; 复制      2.重启 systemctlrest

  • 欢迎来到网络对抗路 实验四 恶意代码分析

    目录一、实验目标与内容1、实验目标与内容2、实践内容2.1、系统运行监控2.2、恶意软件分析二、实践步骤1、使用schtasks指令监控系统2、使用sysmon工具监控系统3、恶意软件分析3.2静态分析-使用VirusTotal分析恶意软件3.3静态分析-使用PEiD分析恶意软件3.3静态分析-使用PEExplorer分析恶意软件3.4动态分析-使用wireshark对后门软件进行分析3.4动态分析-使用Systracer进行分析四、实验中的问题五、实验感想六、回答问题 一、实验目标与内容 1、实验目标与内容 监控你自己系统的运行状态,看有没有可疑的程序在运行。 分析一个恶意软件,就分析Exp2或Exp3中生成后门软件;分析工具尽量使用原生指令或sysinternals,systracer套件 假定将来工作中你觉得自己的主机有问题,就可以用实验中的这个思路,先整个系统监控看能不能找到可疑对象,再对可疑对象进行进一步分析,好确认其具体的行为与性质。 2、实践内容 2.1、系统运行监控 使用如计划任务,每隔一分钟记录自己的电脑有哪些程序在联网,连接的外部IP是哪里。运行一段时间并分析

  • Java lambda 表达式的熟练应用

    Java8刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动。特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里。在Java8之前,如果想将行为传入函数,仅有的选择就是匿名类,需要6行代码。而定义行为最重要的那行代码,却混在中间不够突出。Lambda表达式取代了匿名类,取消了模板,允许用函数式风格编写代码。这样有时可读性更好,表达更清晰。在Java生态系统中,函数式表达与对面向对象的全面支持是个激动人心的进步。将进一步促进并行第三方库的发展,充分利用多核CPU。尽管业界需要时间来消化Java8,但我认为任何严谨的Java开发者都不应忽视此次Java发布的核心特性,即lambda表达式、函数式接口、流API、默认方法和新的Date以及TimeAPI。作为开发人员,我发现学习和掌握lambda表达式的最佳方法就是勇于尝试,尽可能多练习lambda表达式例子。鉴于受Java8发布的影响最大的是Java集合框架(JavaCollectionsframework),所以最好练习流API和lambda表达式,用于对列表(L

  • 一手遮天 Android - Native Development Kit: NDK 简单示例

    项目地址https://github.com/webabcd/AndroidDemo 作者webabcd 一手遮天Android-NativeDevelopmentKit:NDK简单示例 示例如下: /ndk/NdkDemo1.java /** *NDK的简单示例 * *1、先配置ndk-build *在File->Settings->Tools->ExternalTools中新增一项 *name:ndk-build *Program:F:\Android\sdk\android-ndk-r23\ndk-build.cmd *Arguments:NDK_LIBS_OUT=D:\gitroot\AndroidDemo\app\src\main\jniLibs *Workingdirectory:D:\gitroot\AndroidDemo\app\src\main * *2、在app\src\main下新建jni目录(用于保存源代码文件) *在app\src\main下新建jniLibs目录(用于保存编译后的so文件) * *3、在jni文件夹上点击右键,然后单击E

  • Kubernetes API访问控制

    KubernetesAPI访问控制 kubernetes主要通过APIserver对外提供服务,对于这样的系统来说,请求访问的安全性是非常重要的考虑因素。如果不对请求加以限制,那么会导致请求被滥用,甚至黑客的攻击。 apiserver的本质是一个web服务器,底层代码是基于go-restful这个web框架搭建的。传统的web服务器在安全方面一般都会提供认证、授权机制,以过滤器的方式实现。apiserver此外还提供了准入控制。 kubernetes对于通过https访问API的请求会经过三个步骤,前两个是认证和授权,认证解决用户是谁的问题,授权解决用户能做什么的问题。第三个是准入控制,也能在一定程度上提高安全性,不过更多的是资源管理方面的作用。 一般到达apiserver的请求分为两类: 用户对apiserver的请求(kubectl客户端、客户端库或者构造REST请求来访问kubernetesAPI); pod中业务逻辑与apiserver之间的交互。 当请求到达API时,会经历身份认证、鉴权和准入控制三个步骤。当然只有在通过https访问的时候才会经历这三个步骤,http

相关推荐

推荐阅读