C#使用Quartz.NET详细讲解

2023-11-07

Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等。

你曾经需要应用执行一个任务吗?这个任务每天或每周星期二晚上11:30,或许仅仅每个月的最后一天执行。一个自动执行而无须干预的任务在执行过程中如果发生一个严重错误,应用能够知到其执行失败并尝试重新执行吗?你和你的团队是用.NET编程吗?如果这些问题中任何一个你回答是,那么你应该使用Quartz.NET调度器。 Quartz.NET允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz.NET的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业.

Quartz.NET入门

要开始使用 Quartz.NET,需要用 Quartz.NET API 对项目进行配置。步骤如下:

1. 到http://quartznet.sourceforge.net/download.html下载 Quartz.NET API,最新版本是0.6

2. 解压缩Quartz.NET-0.6.zip 到目录,根据你的项目情况用Visual Studio 2003或者Visual Studio 2005打开相应工程,编译。你可以将它放进自己的应用中。Quartz.NET框架只需要少数的第三方库,并且这些三方库是必需的,你很可能已经在使用这些库了。

3. 在Quartz.NET有一个叫做quartz.properties的配置文件,它允许你修改框架运行时环境。缺省是使用Quartz.dll里面的quartz.properties文件。当然你可以在应用程序配置文件中做相应的配置,下面是一个配置文件示例:

<? xml version="1.0" encoding="utf-8" ?>

< configuration >

< configSections >

< section name ="quartz" type ="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />

</ configSections >

< quartz >

< add key ="quartz.scheduler.instanceName" value ="ExampleDefaultQuartzScheduler" />

< add key ="quartz.threadPool.type" value ="Quartz.Simpl.SimpleThreadPool, Quartz" />

< add key ="quartz.threadPool.threadCount" value ="10" />

< add key ="quartz.threadPool.threadPriority" value ="2" />

< add key ="quartz.jobStore.misfireThreshold" value ="60000" />

< add key ="quartz.jobStore.type" value ="Quartz.Simpl.RAMJobStore, Quartz" />

</ quartz >

</ configuration >

为了方便读者,我们使用Quartz.NET的例子代码来解释,现在来看一下 Quartz API 的主要组件。

调度器和作业

Quartz.NET框架的核心是调度器。调度器负责管理Quartz.NET应用运行时环境。调度器不是靠自己做所有的工作,而是依赖框架内一些非常重要的部件。Quartz不仅仅是线程和线程管理。为确保可伸缩性,Quartz.NET采用了基于多线程的架构。 启动时,框架初始化一套worker线程,这套线程被调度器用来执行预定的作业。这就是Quartz.NET怎样能并发运行多个作业的原理。Quartz.NET依赖一套松耦合的线程池管理部件来管理线程环境。作业是一个执行任务的简单.NET类。任务可以是任何C#\VB.NET代码。只需你实现Quartz.IJob接口并且在出现严重错误情况下抛出JobExecutionException异常即可。

IJob接口包含唯一的一个方法Execute(),作业从这里开始执行。一旦实现了IJob接口和Execute ()方法,当Quartz.NET确定该是作业运行的时候,它将调用你的作业。Execute()方法内就完全是你要做的事情。

通过实现 Quartz.IJob接口,可以使 .NET 类变成可执行的。清单 1 提供了 Quartz.IJob作业的一个示例。这个类用一条非常简单的输出语句覆盖了 Execute(JobExecutionContext context) 方法。这个方法可以包含我们想要执行的任何代码(所有的代码示例都基于 Quartz.NET 0.6 ,它是编写这篇文章时的稳定发行版)。

清单 1:作业

using System;

using System.Collections.Generic;

using System.Text;

using Common.Logging;

using Quartz;

namespace QuartzBeginnerExample

{

public class SimpleQuartzJob : IJob

{

private static ILog _log = LogManager.GetLogger( typeof (SimpleQuartzJob));

/// <summary>

/// Called by the <see cref="IScheduler" /> when a

/// <see cref="Trigger" /> fires that is associated with

/// the <see cref="IJob" /> .

/// </summary>

public virtual void Execute(JobExecutionContext context)

{

try

{

// This job simply prints out its job name and the

// date and time that it is running

string jobName = context.JobDetail.FullName;

_log.Info(
" Executing job: " + jobName + " executing at " + DateTime.Now.ToString( " r " ));

}

catch (Exception e)

{

_log.Info(
" --- Error in job! " );

JobExecutionException e2
= new JobExecutionException(e);

// this job will refire immediately

e2.RefireImmediately
= true ;

throw e2;

}

}

}

}

请注意,Execute 方法接受一个 JobExecutionContext 对象作为参数。这个对象提供了作业实例的运行时上下文。特别地,它提供了对调度器和触发器的访问,这两者协作来启动作业以及作业的 JobDetail 对象的执行。Quartz.NET 通过把作业的状态放在 JobDetail 对象中并让 JobDetail 构造函数启动一个作业的实例,分离了作业的执行和作业周围的状态。JobDetail 对象储存作业的侦听器、群组、数据映射、描述以及作业的其他属性。

作业和触发器:

Quartz.NET设计者做了一个设计选择来从调度分离开作业。Quartz.NET中的触发器用来告诉调度程序作业什么时候触发。框架提供了一把触发器类型,但两个最常用的是SimpleTrigger和CronTrigger。SimpleTrigger为需要简单打火调度而设计。

典型地,如果你需要在给定的时间和重复次数或者两次打火之间等待的秒数打火一个作业,那么SimpleTrigger适合你。另一方面,如果你有许多复杂的作业调度,那么或许需要CronTrigger。

CronTrigger是基于Calendar-like调度的。当你需要在除星期六和星期天外的每天上午10点半执行作业时,那么应该使用CronTrigger。正如它的名字所暗示的那样,CronTrigger是基于Unix克隆表达式的。

Cron表达式被用来配置CronTrigger实例。Cron表达式是一个由7个子表达式组成的字符串。每个子表达式都描述了一个单独的日程细节。这些子表达式用空格分隔,分别表示:

1. Seconds 秒

2. Minutes 分钟

3. Hours 小时

4. Day-of-Month 月中的天

5. Month 月

6. Day-of-Week 周中的天

7. Year (optional field) 年(可选的域)

一个cron表达式的例子字符串为"0 0 12 ? * WED",这表示“每周三的中午12:00”。

单个子表达式可以包含范围或者列表。例如:前面例子中的周中的天这个域(这里是"WED")可以被替换为"MON-FRI", "MON, WED, FRI"或者甚至"MON-WED,SAT"。

通配符('*')可以被用来表示域中“每个”可能的值。因此在"Month"域中的*表示每个月,而在Day-Of-Week域中的*则表示“周中的每一天”。

所有的域中的值都有特定的合法范围,这些值的合法范围相当明显,例如:秒和分域的合法值为0到59,小时的合法范围是0到23,Day-of-Month中值得合法凡范围是0到31,但是需要注意不同的月份中的天数不同。月份的合法值是0到11。或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 及DEC来表示。Days-of-Week可以用1到7来表示(1=星期日)或者用字符串SUN, MON, TUE, WED, THU, FRI 和SAT来表示.

'/'字符用来表示值的增量,例如, 如果分钟域中放入'0/15',它表示“每隔15分钟,从0开始”,如果在份中域中使用'3/20',则表示“小时中每隔20分钟,从第3分钟开始”或者另外相同的形式就是'3,23,43'。

'?'字符可以用在day-of-month及day-of-week域中,它用来表示“没有指定值”。这对于需要指定一个或者两个域的值而不需要对其他域进行设置来说相当有用。

'L'字符可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个域中的意义不同。例如,在day-of-month域中的"L"表示这个月的最后一天,即,一月的31日,非闰年的二月的28日。如果它用在day-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week域中,这个字符跟在别的值后面,则表示"当月的最后的周XXX"。例如:"6L" 或者 "FRIL"都表示本月的最后一个周五。当使用'L'选项时,最重要的是不要指定列表或者值范围,否则会导致混乱。

'W' 字符用来指定距离给定日最接近的周几(在day-of-week域中指定)。例如:如果你为day-of-month域指定为"15W",则表示“距离月中15号最近的周几”。

'#'表示表示月中的第几个周几。例如:day-of-week域中的"6#3" 或者 "FRI#3"表示“月中第三个周五”。

作为一个例子,下面的Quartz.NET克隆表达式将在星期一到星期五的每天上午10点15分执行一个作业。

0 15 10 ? * MON-FRI

下面的表达式

0 15 10 ? * 6L 2007-2010

将在2007年到2010年的每个月的最后一个星期五上午10点15分执行作业。你不可能用SimpleTrigger来做这些事情。你可以用两者之中的任何一个,但哪个跟合适则取决于你的调度需要。

清单 2 中的 SimpleTrigger 展示了触发器的基础:

清单2 SimpleTriggerRunner.cs

using System;

using System.Collections.Generic;

using System.Text;

using Common.Logging;

using Quartz;

using Quartz.Impl;

namespace QuartzBeginnerExample

{

public class SimpleTriggerRunner

{

public virtual void Run()

{

ILog log
= LogManager.GetLogger( typeof (SimpleTriggerExample));

log.Info(
" ------- Initializing ------------------- " );

// First we must get a reference to a scheduler

ISchedulerFactory sf
= new StdSchedulerFactory();

IScheduler sched
= sf.GetScheduler();

log.Info(
" ------- Initialization Complete -------- " );

log.Info(
" ------- Scheduling Jobs ---------------- " );

// jobs can be scheduled before sched.start() has been called

// get a "nice round" time a few seconds in the future...

DateTime ts
= TriggerUtils.GetNextGivenSecondDate( null , 15 );

// job1 will only fire once at date/time "ts"

JobDetail job
= new JobDetail( " job1 " , " group1 " , typeof (SimpleJob));

SimpleTrigger trigger
= new SimpleTrigger( " trigger1 " , " group1 " );

// set its start up time

trigger.StartTime
= ts;

// set the interval, how often the job should run (10 seconds here)

trigger.RepeatInterval
= 10000 ;

// set the number of execution of this job, set to 10 times.

// It will run 10 time and exhaust.

trigger.RepeatCount
= 100 ;

// schedule it to run!

DateTime ft
= sched.ScheduleJob(job, trigger);

log.Info(
string .Format( " {0} will run at: {1} and repeat: {2} times, every {3} seconds " ,

job.FullName, ft.ToString(
" r " ), trigger.RepeatCount, (trigger.RepeatInterval / 1000 )));

log.Info(
" ------- Starting Scheduler ---------------- " );

// All of the jobs have been added to the scheduler, but none of the jobs

// will run until the scheduler has been started

sched.Start();

log.Info(
" ------- Started Scheduler ----------------- " );

log.Info(
" ------- Waiting 30 seconds... -------------- " );

try

{

// wait 30 seconds to show jobs

Thread.Sleep(
30 * 1000 );

// executing...

}

catch (ThreadInterruptedException)

{

}

log.Info(
" ------- Shutting Down --------------------- " );

sched.Shutdown(
true );

log.Info(
" ------- Shutdown Complete ----------------- " );

// display some stats about the schedule that just ran

SchedulerMetaData metaData
= sched.GetMetaData();

log.Info(
string .Format( " Executed {0} jobs. " , metaData.NumJobsExecuted));

}

}

}

清单 2 开始时实例化一个 SchedulerFactory,获得此调度器。就像前面讨论过的,创建 JobDetail 对象时,它的构造函数要接受一个 Job 作为参数。顾名思义,SimpleTrigger 实例相当原始。在创建对象之后,设置几个基本属性以立即调度任务,然后每 10 秒重复一次,直到作业被执行 100 次。

还有其他许多方式可以操纵 SimpleTrigger。除了指定重复次数和重复间隔,还可以指定作业在特定日历时间执行,只需给定执行的最长时间或者优先级(稍后讨论)。执行的最长时间可以覆盖指定的重复次数,从而确保作业的运行不会超过最长时间。

清单 3 显示了 CronTrigger 的一个示例。请注意 SchedulerFactory、Scheduler 和 JobDetail 的实例化,与 SimpleTrigger 示例中的实例化是相同的。在这个示例中,只是修改了触发器。这里指定的 cron 表达式(“0/5 * * * * ?”)安排任务每 5 秒执行一次。

清单3 CronTriggerRunner.cs

using System;

using System.Collections.Generic;

using System.Text;

using Common.Logging;

using Quartz;

using Quartz.Impl;

using System.Threading;

namespace QuartzBeginnerExample

{

public class CronTriggerRunner

{

public virtual void Run()

{

ILog log
= LogManager.GetLogger( typeof (CronTriggerRunner));

log.Info(
" ------- Initializing ------------------- " );

// First we must get a reference to a scheduler

ISchedulerFactory sf
= new StdSchedulerFactory();

IScheduler sched
= sf.GetScheduler();

log.Info(
" ------- Initialization Complete -------- " );

log.Info(
" ------- Scheduling Jobs ---------------- " );

// jobs can be scheduled before sched.start() has been called

// job 1 will run every 20 seconds

JobDetail job
= new JobDetail( " job1 " , " group1 " , typeof (SimpleQuartzJob));

CronTrigger trigger
= new CronTrigger( " trigger1 " , " group1 " , " job1 " , " group1 " );

trigger.CronExpressionString
= " 0/20 * * * * ? " ;

sched.AddJob(job,
true );

DateTime ft
= sched.ScheduleJob(trigger);

log.Info(
string .Format( " {0} has been scheduled to run at: {1} and repeat based on expression: {2} " , job.FullName, ft.ToString( " r " ), trigger.CronExpressionString));

log.Info(
" ------- Starting Scheduler ---------------- " );

// All of the jobs have been added to the scheduler, but none of the

// jobs

// will run until the scheduler has been started

sched.Start();

log.Info(
" ------- Started Scheduler ----------------- " );

log.Info(
" ------- Waiting five minutes... ------------ " );

try

{

// wait five minutes to show jobs

Thread.Sleep(
300 * 1000 );

// executing...

}

catch (ThreadInterruptedException)

{

}

log.Info(
" ------- Shutting Down --------------------- " );

sched.Shutdown(
true );

log.Info(
" ------- Shutdown Complete ----------------- " );

SchedulerMetaData metaData
= sched.GetMetaData();

log.Info(
string .Format( " Executed {0} jobs. " , metaData.NumJobsExecuted));

}

}

}

如上所示,只用作业和触发器,就能访问大量的功能。但是,Quartz 是个丰富而灵活的调度包,对于愿意研究它的人来说,它还提供了更多功能。下一节讨论 Quartz 的一些高级特性。

作业管理和存储

作业一旦被调度,调度器需要记住并且跟踪作业和它们的执行次数。如果你的作业是30分钟后或每30秒调用,这不是很有用。事实上,作业执行需要非常准确和即时调用在被调度作业上的Execute()方法。Quartz通过一个称之为作业存储(JobStore)的概念来做作业存储和管理。

有效作业存储

Quartz提供两种基本作业存储类型。第一种类型叫做RAMJobStore,它利用通常的内存来持久化调度程序信息。这种作业存储类型最容易配置、构造和运行。Quartz.net缺省使用的就是RAMJobStore。对许多应用来说,这种作业存储已经足够了。

然而,因为调度程序信息是存储在被分配在内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。如果你需要在重新启动之间持久化调度信息,则将需要第二种类型的作业存储。为了修正这个问题,Quartz.NET 提供了 AdoJobStore。顾名思义,作业仓库通过 ADO.NET把所有数据放在数据库中。数据持久性的代价就是性能降低和复杂性的提高。它将所有的数据通过ADO.NET保存到数据库可中。它的配置要比RAMJobStore稍微复杂,同时速度也没有那么快。但是性能的缺陷不是非常差,尤其是如果你在数据库表的主键上建立索引。

设置AdoJobStore

AdoJobStore几乎可以在任何数据库上工作,它广泛地使用Oracle, MySQL, MS SQLServer2000, HSQLDB, PostreSQL 以及 DB2。要使用AdoJobStore,首先必须创建一套Quartz使用的数据库表,可以在Quartz 的database\tables找到创建库表的SQL脚本。如果没有找到你的数据库类型的脚本,那么找到一个已有的,修改成为你数据库所需要的。需要注意的一件事情就是所有Quartz库表名都以QRTZ_作为前缀(例如:表"QRTZ_TRIGGERS",及"QRTZ_JOB_DETAIL")。实际上,可以你可以将前缀设置为任何你想要的前缀,只要你告诉AdoJobStore那个前缀是什么即可(在你的Quartz属性文件中配置)。对于一个数据库中使用多个scheduler实例,那么配置不同的前缀可以创建多套库表,十分有用。

一旦数据库表已经创建,在配置和启动AdoJobStore之前,就需要作出一个更加重要的决策。你要决定在你的应用中需要什么类型的事务。如果不想将scheduling命令绑到其他的事务上,那么你可以通过对JobStore使用JobStoreTX来让Quartz帮你管理事务(这是最普遍的选择)。

Quartz.net 作业调度框架所提供的 API 在两方面都表现极佳:既全面强大,又易于使用。Quartz 可以用于简单的作业触发,也可以用于复杂的 Ado.net持久的作业存储和执行。

示例下载www.cnblogs.com/Files/shanyou/QuartzBeginnerExample.zip  基于 Quartz.net 的示例 (C#代码 )   QuartzBeginnerExample.zip    324KB 

获取Quartz.net :quartznet.sourceforge.net/download.html:.NET应用程序的开放源码作业调度解决方案

作者:hb_cattle

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#使用Quartz.NET详细讲解 的相关文章

  • 检测到 NuGet 包的版本冲突

    我正在开发 ASP Net core 2 1 Web 应用程序项目 我的解决方案中有 1 个项目和 3 个其他库 它是高级架构 数据访问层 DAL 业务层 BL 公共层 CL 所以我需要添加引用来连接一些库和项目 我已经添加了CL参考我的项
  • 在 OpenCL 中将函数作为参数传递

    是否可以在 OpenCL 1 2 中将函数指针传递给内核 我知道可以用C实现 但不知道如何在OpenCL的C中实现 编辑 我想做这篇文章中描述的同样的事情 在 C 中如何将函数作为参数传递 https stackoverflow com q
  • 通信对象 System.ServiceModel.Channels.ServiceChannel 不能用于通信

    通信对象System ServiceModel Channels ServiceChannel 无法用于通信 因为它处于故障状态 这个错误到底是什么意思 我该如何解决它 您收到此错误是因为您让服务器端发生 NET 异常 并且您没有捕获并处理
  • 在 C++11 中省略返回类型

    我最近发现自己在 C 11 模式下的 gcc 4 5 中使用了以下宏 define RETURN x gt decltype x return x 并编写这样的函数 template
  • ASP .NET MVC,创建类似路由配置的永久链接

    我需要帮助在 MVC 网站中创建类似 URL 路由的永久链接 Slug 已设置为 www xyz com profile slug 代码为 routes MapRoute name Profile url profile slug defa
  • TextBox 焦点的 WinForms 事件?

    我想添加一个偶数TextBox当它有焦点时 我知道我可以用一个简单的方法来做到这一点textbox1 Focus并检查布尔值 但我不想那样做 我想这样做 this tGID Focus new System EventHandler thi
  • 为什么 BOOST_FOREACH 不完全等同于手工编码的?

    From 增强文档 http www boost org doc libs 1 48 0 doc html foreach html foreach introduction what is literal boost foreach li
  • C++派生模板类继承自模板基类,无法调用基类构造函数[重复]

    这个问题在这里已经有答案了 我试图从基类 模板 继承 派生类也是模板 它们具有相同的类型 T 我收到编译错误 非法成员初始化 Base 不是基类或成员 为什么 如何调用基类构造函数 include
  • 单元测试失败,异常代码为 c0000005

    我正在尝试使用本机单元测试项目在 Visual Studios 2012 中创建单元测试 这是我的测试 TEST METHOD CalculationsRoundTests int result Calculations Round 1 0
  • 组合框项目为空但数据源已满

    将列表绑定到组合框后 其 dataSource Count 为 5 但组合框项目计数为 0 怎么会这样 我习惯了 Web 编程 而且这是在 Windows 窗体中进行的 所以不行combo DataBind 方法存在 这里的问题是 我试图以
  • 用于从字符串安全转换的辅助函数

    回到 VB6 我编写了一些函数 让我在编码时无需关心字符串的 null 和 数字的 null 和 0 等之间的区别 编码时 没有什么比添加特殊情况更能降低我的工作效率了用于处理可能导致一些不相关错误的数据的代码 9999 10000 如果我
  • “MyClass”的类型初始值设定项引发异常

    以下是我的Windows服务代码 当我调试代码时 我收到错误 异常 CSMessageUtility CSDetails 的类型初始值设定项引发异常 using System using System Collections Generic
  • std::bind 重载解析

    下面的代码工作正常 include
  • 如何排列表格中的项目 - MVC3 视图 (Index.cshtml)

    我想使用 ASP NET MVC3 显示特定类型食品样本中存在的不同类型维生素的含量 如何在我的视图 Index cshtml 中显示它 an example 这些是我的代码 table tr th th foreach var m in
  • 通过等待任务或访问其 Exception 属性都没有观察到任务的异常

    这些是我的任务 我应该如何修改它们以防止出现此错误 我检查了其他类似的线程 但我正在使用等待并继续 那么这个错误是怎么发生的呢 通过等待任务或访问其 Exception 属性都没有观察到任务的异常 结果 未观察到的异常被终结器线程重新抛出
  • 以编程方式使用自定义元素创建网格

    我正在尝试以编程方式创建一个网格 并将自定义控件作为子项附加到网格中 作为 2x2 矩阵中的第 0 行第 0 列 为了让事情变得更棘手 我使用了 MVVM 设计模式 下面是一些代码可以帮助大家理解这个想法 应用程序 xaml cs base
  • boost::program_options:带有固定和可变标记的参数?

    是否可以在 boost program options 中使用此类参数 program p1 123 p2 234 p3 345 p12 678 即 是否可以使用第一个标记指定参数名称 例如 p 后跟一个数字 是动态的吗 我想避免这种情况
  • Swagger 为 ASP.CORE 3 中的字典生成错误的 URL

    当从查询字符串中提取的模型将字典作为其属性之一时 Swagger 会生成不正确的 URL 如何告诉 Swagger 更改 URL 中字典的格式或手动定义输入参数模式而不自动生成 尝试使用 Swashbuckle 和 NSwag 控制器 pu
  • 从类模板参数为 asm 生成唯一的字符串文字

    我有一个非常特殊的情况 我需要为类模板中声明的变量生成唯一的汇编程序名称 我需要该名称对于类模板的每个实例都是唯一的 并且我需要将其传递给asm关键字 see here https gcc gnu org onlinedocs gcc 12
  • 如何确定母版页中正在显示哪个子页?

    我正在母版页上编写代码 我需要知道正在显示哪个子 内容 页面 我怎样才能以编程方式做到这一点 我用这个 string pageName this ContentPlaceHolder1 Page GetType FullName 它以 AS

随机推荐

  • 数据结构练习题-1

    1 简述下列概念 数据 数据元素 数据项 数据对象 数据结构 逻辑结构 存储结构 抽象数据类型 答案 数据 是客观事物的符号表示 指所有能输入到计算机中并被计算机程序处理的符号的总称 如数学计算中用到的整数和实数 文本编辑所用到的字符串 多
  • CH4-串、数组和广义表

    文章目录 4 1 串的定义 4 2 案例引入 4 3 串的类型定义 存储结构及运算 4 3 1 顺序串 4 3 2 链串 4 3 3模式匹配算法 BF算法 KMP算法 4 4 数组 4 4 1抽象数据类型定义 4 4 2数组的顺序存储 4
  • 最新区块链开发教程汇总

    区块链的重要性已经毋庸置疑 但对大多数跃跃欲试的开发者而言 去中心化思想 非对称加密 共识算法等技术点的理解和运用 都是入门区块链开发的挑战 合适的区块链开发教程可以极大地缩短区块链开发的学习周期 因此 本文汇总整理了以太坊 比特币 EOS
  • 如何用C语言实现多态?

    多态 Polymorphism 是指面向对象程序运行时 相同的消息可能会送给多个不同的类之对象 系统依据对象所属类 引发对应类的方法 而有不同的行为 简单来说 所谓多态意指相同的消息给予不同的对象会引发不同的动作 在C语言中 可以通过结构体
  • shell脚本awk之变量传递

    一 在shell脚本中awk引用shell变量 1 双引号加单引号的形式 1 awk引用系统变量 bin bash awk BEGIN print HOSTNAME 执行结果 root node1 pangbing test sh test
  • 主板中的Win10/win8.1 WHQL支持是否要开启

    主板中的Win10 win8 1 WHQL支持是否要开启 在新式的电脑主板上会有Windows 10 8 1 WHQL支持开启的选项 这个选项的开启和关闭分别代表什么意义呢 这其实还要从UEFI和Legacy两种不同BIOS的说起 Lega
  • 生命在于折腾——MacOS(Inter)渗透测试环境搭建

    一 前景提要 之前使用的是2022款M2芯片的MacBook Air 13寸 不得不说 是真的续航好 轻薄 刚开始我了解到M芯片的底层是ARM架构 我觉得可以接受 虚拟机用的不多 但在后续的使用过程中 发现卡脖子就是卡脖子 随后换了联想R9
  • Linux内核的全局变量

    全局变量 srctree if KBUILD SRC KBUILD SRC CURDIR objtree CURDIR src srctree obj objtree VPATH srctree if KBUILD EXTMOD KBUIL
  • Blender人物骨骼绑定

    Blender人物骨骼绑定 1 建立骨骼父子关系 某些物体依附到其他物体上并成为它的子物体 可由骨骼按E键直接分裂出子骨骼 2 将骨骼建立和三维模型的父子关系 3 设置反向运动学 正常的正向运动学是FK 也就是父骨骼带动子骨骼 而如果想要实
  • mysql中的group by 和 having使用

    mysql中的group by 和 having 使用 理论 sql中的group by 用法解析 Group By语句从英文的字面意义上理解就是 根据 by 一定的规则进行分组 Group 它的作用是通过一定的规则将一个数据集划分成若干个
  • SDL 使用 framebuffer

    SDL 窗口系统 基于X11或WayLand协议 OpenGL 与硬件无关 通过发命令给GPU完成绘制工作 EGL 与硬件相关 是窗口系统 SDL 和OpenGL媒介 SDL Simple DirectMedia Layer 是一套开放源代
  • SpringBoot统一接口返回

    文章目录 前言 思路 1 定义标识 可以定义一个注解作为标识 2 对Controller或者method打上标识 3 请求时判断是否存在该标识 可以利用拦截器 4 对结果重新写入 前言 前后分离时 我们要定义好统一的接口返回格式 eg co
  • PCL点云处理之泊松曲面重建(一百六十一)

    PCL点云处理之泊松曲面重建 一百六十一 一 算法介绍 二 算法实现 1 代码 2 效果 一 算法介绍 泊松曲面重建基于泊松方程 根据泊松方程使用矩阵迭代求出近似解 采用移动立方体算法提取等值面 对所测数据点集重构出被测物体的模型 泊松方程
  • 【C语言基础】标准库函数strcat的使用

    文章目录 C语言基础 标准库函数strcat的使用 一 功能解释 二 函数原型 三 使用示例 1 使用字符数组作为第一个参数 2 使用指向字符数组的指针作为第一个参数 3 使用字符串常量作为第二个参数 4 使用字符数组作为第二个参数 5 使
  • PyTorch学习笔记(20) ——激活函数

    0 前言 本博客内容翻译自纽约大学数据科学中心在2020发布的 Deep Learning 课程的Activation Functions and Loss Functions部分 废话不多说 下面直接开始吧 1 激活函数 本内容将回顾一些
  • js删除数组中指定元素

    js删除数组中某一项或几项的几种方法 一 删除第一个元素 1 shift 方法用于把数组的第一个元素从其中删除 并返回第一个元素的值 注意 此方法改变数组的长度 提示 移除数组末尾的元素可以使用 pop 方法 let arr 1 2 3 4
  • LEARN C++(Methods)

    Getting the most out of these tutorials As you go through these tutorials we recommend a number of practices to maximize
  • CSS 之实现它们它们和它们

    一 CSS画图形 1 用CSS画三角形 首先 需要把元素的宽度 高度设为0 然后设置边框样式
  • mkdocs 使用说明

    mkdocs 使用说明 安装 pip3 install mkdocs 1 4 2 创建项目 mkdocs new my project cd my project 修改 mkdocs yml site name My Docs site u
  • C#使用Quartz.NET详细讲解

    Quartz NET是一个开源的作业调度框架 是OpenSymphony 的 Quartz API的 NET移植 它用C 写成 可用于winform和asp net应用中 它提供了巨大的灵活性而不牺牲简单性 你能够用它来为执行一个作业而创建