首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Android Studio 插件开发详解一:入门练手

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78112003 本文出自【赵彦军的博客】 一:概述 相信大家在使用Android Studio的时候,或多或少的会使用一些插件,适当的配合插件可以帮助我们提升一定的开发效率,更加快乐。例如: https://github.com/zzz40500/GsonFormat 可以帮助我们从Gson转化为实体类 https://github.com/avast/android-butterknife-zelezny 可以帮助我们更加方便的使用butterknife https://github.com/Skykai521/ECTranslation 可以帮助在IDE里面完成英文->中文的翻译 其他更多好用的插件详见 Android Studio 常见插件收藏 有句话叫做授人以鱼不如授人以渔,不能一直跟随着别人的脚步去使用插件了,有必要去学习编写插件,当自己有好的创意的时候,就可以自己实现了。今天的内容就是:自己编写一个Android Studio插件。 二:前期准备 在正式动工之前,我们需要做一些准备工作,否则后面的内容难以展开。 1、 安装 jdk ,配置环境变量。安装过程这里不细说,直接搜索即可。 2、 你需要了解 groovy 的相关知识,包括 groovy 环境搭建,groovy 开发工具了解,groovy 语法了解,这些不在这里细说,具体的知识点可以参考我的博客 Groovy 使用完全解析 三:Android Studio Plugin 开发工具 开发工具我们选择用 IntelliJ IDEA 下载地址: https://www.jetbrains.com/idea/ 在官网中 IntelliJ IDEA 有两个版本 Ultimate 、Community。Ultimate 是收费版,Community 是免费版。对于收费版有经济能力的可以考虑,但是我们的插件开发用免费版 Community 就可以了。 IntelliJ IDEA 的安装过程,这里不细说。 四、新建Plugin Project 在打开的IntelliJ IDEA 中选择 File | New | Project groovy 我们暂时不勾选,点击 Next 最后输入项目名称确定,点击 finish 完成创建 五、配置插件项目 创建好的 Plugin 项目中,会默认生成一个 plugin.xml 的配置文件 其中可以修改该插件项目的相关配置信息,比如插件名称、插件版本号等,如下图 各标签意义具体为: [ id ] 插件id,类似于Android项目的包名,不能和其他插件项目重复,所以推荐使用com.xxx.xxx的格式 [ name ] 插件名称,别人在官方插件库搜索你的插件时使用的名称 [ version ] 插件版本号 [ vendor ] 插件发布者信息,可以添加邮箱链接 [ description ] 插件描述信息,在这里可以介绍你的插件内容,支持HTML标签 [ change-notes ] 插件版本变更日志,支持HTML标签 [ idea-version ] 对IntelliJ IDEA软件支持本插件版本号 分为since-build最低版本 和 until-build最高版本,两个属性可以任选一或者同时使用 官网有详细介绍 www.jetbrains.org/intellij/sd… 大体规则为 since-build <= 支持版本 < until-build [ extensions ] 自定义扩展,暂时用不到 [ actions ] 具体的插件动作,后面会介绍 配置中填写的信息,会在别人搜索你插件的时候展现介绍,在 File | Settings | Plugins 中查看已有插件,或者再点击 Browse respositories 中浏览插件中心里其他人发布的插件。当选中一个插件时,右侧就可以看到plugin.xml中配置的信息了,同样这里也可以进行插件的删除和添加安装操作,每次操作都需要重启软件后才能生效。 六、开始编写插件 项目创建好时有一个src文件夹,可以在其中File | New …新建文件, 主要有这么几种针对插件的特殊文件类型 GUI Form:表单界面 Dialog:对话框 XXXComponent:作用域类,其中又分为Application、Project、Module 分为作用于不同范围 Action:处理插件交互行为的类 在项目中的 src 目录中,New | Plugin Devkit | Action Action的创建的对话框如下: Action ID: 动作ID,推荐用“插件名.XXAction”的格式 Class Name:编写Action的类文件名 Name:动作在菜单选项中展示的名字 Description:动作描述 Groups:定义这个动作选项所属的组,比如EditMenu就对应IDE菜单栏上的Edit,CodeMenu就对应菜单栏上的Code Actions:是当前选中Groups下已有的Action动作,比如上图示如果我们选择CodeMenu就会展示Code中已有的几个选项 Anchor:用来指定动作选项在Groups中的位置,Frist就是最上面、Last是最下面,也可以设在某个选项的上/下方 Keyboard Shortcuts:调用插件Action的快捷键,可以不填,要注意热键冲突 创建好Action后,会自动在plugin.xml配置文件的actions标签中新增一个对应的Action动作信息。 <actions> <!-- Add your actions here --> <action id="TestID" class="com.Test" text="Test" description="Test"> <add-to-group group-id="EditMenu" anchor="first"/> <keyboard-shortcut keymap="$default" first-keystroke="ctrl Q"/> </action> </actions> 注意 这里的信息我们都可以再次修改,但是 class name 修改时要注意和类文件名匹配 可以修改添加多个,即在不同菜单中都可以选择使用 同一个 group下多个 action 的 id 不能重复. src下创建好的Action类会默认继承 AnAction,然后实现 actionPerformed 方法,在方法中添加如下代码,让点击这个 Action 的时候弹出一个输入框。 import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; public class Test extends AnAction { @Override public void actionPerformed(AnActionEvent e) { // TODO: insert action logic here Project project = e.getData(PlatformDataKeys.PROJECT); String txt = Messages.showInputDialog(project, "What is your name?", "Input your name", Messages.getQuestionIcon()); Messages.showMessageDialog(project, "Hello, " + txt + "!\n I am glad to see you.", "Information", Messages.getInformationIcon()); } } 写好代码后,run运行项目,此时会自动启动一个新的IntelliJ IDEA项目,这个新项目里就会包含我们刚编写的插件选项了。 七、打包 比较简单,直接在顶部主菜单栏中选择 Build | Prepare Plugin Module XXX For Deployment 即可。 打包前要注意把 plugin.xml 配置文件中的相关信息填写完整。 打完包后,将会生成 .Jar 包 类似于安卓打包生产的apk,这个时候你就可以把它丢给别人使用了 八、Android Studio 测试插件 在上一章中,我们已经打包好插件 Plugin.jar ,现在我们在 Android Studion 测试一下。 8.1 安装插件 File –> Settings –> Plugins –> Install plugin from disk 8.2 测试插件 或者按快捷键 Ctrl + Q 启动插件。 九、上传插件 IntelliJ的插件也有一个市场,是官方提供的,可以在平台上发布自己的插件 地址:https://plugins.jetbrains.com/ 打开插件中心,注册好账号,然后选择 Upload Plugin 将你生成的插件jar包上传,然后选择分类,最后确认完成上传。 十、参考资料 【Android Studio Plugin 插件开发教程】https://juejin.im/post/599f7f546fb9a0248c2de496 下一篇:Android Studio 插件开发详解二:工具类 个人微信号:zhaoyanjun125 , 欢迎关注

优秀的个人博客,低调大师

ASP.NET MVC4 入门简介

1、什么是设计模式? 模式的理解 模式是一种解决问题的思路,而不是具体的做法。 设计模式的理解 在软件开发领域,设计模式是为解决开发中某一类问题而提出的一种解决方案。因此,设计模式本质上是思想,而不是代码。设计模式追求的思想上的复用,而不是代码上的复用。 2、ASP.NET MVC概述 ASP.NET MVC是一种构建Web应用程序的框架,它将一般的MVC(Model-View-Controller)模式应用于ASP.NET框架。 MVC将Web应用程序划分为三个主要的部分,以下是MSDN给出的定义: 模型(Model):模型对象是实现应用程序数据域逻辑的应用程序部件。 通常,模型对象会检索模型状态并将其存储在数据库中。 例如,Product 对象可能会从数据库中检索信息,操作该信息,然后将更新的信息写回到 SQL Server 数据库内的 Products 表中。 视图(View):视图是显示应用程序用户界面 (UI) 的组件。 通常,此 UI 是用模型数据创建的。 Products 表的编辑视图便是一个视图示例,该视图基于 Product 对象的当前状态显示文本框、下拉列表和复选框。 控制器(Controller):控制器是处理用户交互、使用模型并最终选择要呈现的视图来显示 UI 的组件。 在 MVC 应用程序中,视图仅显示信息;控制器则用于处理和响应用户输入和交互。 例如,控制器处理查询字符串值,并将这些值传递给模型,而模型可能会使用这些值来查询数据库。 3、ASP.NET MVC的发展历程 我们以一张时间轴线图开始,了解一下ASP.NET MVC的发展历程。 2007年2月,Microsoft公司的Scott Guthrie在旅途中草拟了ASP.NET MVC的内核程序。经过9个预览版本,于2009年3月13日,正式发布ASP.NETMVC1官方版本。 时隔一年,ASP.NETMVC2于2010年3月发布,部分主要特征如下: • 带有自定义模板的UI辅助程序 • 在客户端和服务端基于特性的模型验证 • 强类型的HTML辅助程序 • 改善的Visual Studio开发工具 • 支持将大型应用程序划分为域 • 支持异步控制器 • 使用Html.RenderAction支持渲染网页或网站的某一部分 • 新的辅助函数、使用工具和API增强 2011年1月,ASP.NET MVC3正式推出,部分主要特征如下: • 支持Razor视图引擎 • 支持.NET4数据注解 • 改进了模型验证 • 提供更强的控制和更大的灵活性,支持依赖项解析(Dependency Resolution)和全局操作过滤器(Global Action Filter) • 丰富的JavaScript支持,其中包括非侵入式JavaScript、jQuery验证和JSON绑定 • 支持NuGet,可以用来发布软件,管理整个平台的依赖 2012年9月,ASP.NET MVC4正式发布,新增功能主要包括: • ASP.NET Web API • 增强了默认的项目模板 • 添加使用jQuery Mobile的手机项目模板 • 支持显示模式(Display Mode) • 支持异步控制器的任务 • 捆绑和微小(minification) 2013年10月,ASP.NET MVC5与Visual Studio 2013一起发布,下面列出了一些主要特征: • One ASP.NET • 新的Web项目体验 • ASP.NETIdentity • Bootstrap模板 • 特性路由 • ASP.NET基架 • 身份验证过滤器 • 过滤器重写 4、创建ASP.NET MVC4应用程序 1、选择“文件”->“新建”->“项目”选项,如下图所示: 2、在“新建项目”对话框左侧的“已安装”->“模板”->“Visual C#”列表下,选中Web选项,选择ASP.NET MVC4 Web应用程序,将应用程序命名为MyFirstMvcProject,点击“确定”按钮,如下图所示: 3、在弹出的“新ASP.NET 项目”对话框中,选中“基本”模板,视图引擎选择“Razor”,同时将“创建单元测试项目”勾选上,点击“确定”按钮,如下图所示: 4、至此,一个新的MVC项目已经创建完成,如下图所示: 5、ASP.NET MVC应用程序结构 新的MVC项目创建完成后,会自动向这个项目中创建一些目录,下表介绍了这些目录的主要用途。 目录 用途 App_Data 用于存储想要读取/写入的数据文件 App_Start 用于保存一些功能的配置代码 Content 用于保存CSS、图像和其他站点内容 Controllers 用于保存处理URL请求的控制器类 Models 用于保存表示和操纵数据以及业务对象的类 Scripts 用于保存JavaScript库文件和脚本 Views 用于保存负责呈现输出结果的UI模板文件 6、ASP.NETMVC的约定 在默认情况下,ASP.NET MVC应用程序对约定的依赖性很强,这样就避免了开发人员配置和指定一些项,因为这些项可以根据约定来推断。这个概念通常被称为“习惯优于配置(convention over configration)”。 ASP.NET MVC对于程序结构的约定如下: 1、每个Controller类的名字以Controller结尾,保存在Controller目录中。 2、应用程序的所有视图放在单独的Views目录下。 3、控制器使用的视图是在Views主目录下的,与控制器名称相同的子目录中。 7、WebForm和ASP.NET MVC,为什么MVC更好一些? ASP.NET Webform 后台代码(behind code)——福音与诅咒 我们已经在项目开发中使用过ASP.NETWebform技术,大家会发现它更接近可视化设计,换句话说,开发者只需要从设计面板中拖拽控件即可完成UI,接着在behindcode中实现逻辑代码即可完成最后的Web页面功能。 所以换句话说,当你从设计面板中拖拽一个按钮时,在后台代码中就会生成一个button对象,你只需要在按钮的点击事件中实现事件响应代码即可。 public partial class WebForm1 :System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { // Developers write code here } protected void Button1_Click(object sender, EventArgs e) { // Developers write code here } } 当我们在页面中拖拽一些UI元素时,双击它们即可在后台代码中生成一系列事件响应代码,这些逻辑代码都在ASPX.CS文件中。 这个后台代码文件是ASP.NETWebForm的关键,你可以在这个文件中应用.NET的所有特性,包括事件、委托、HTTP协议以及Session等等。 但是这种behindcode模式有5个问题,下面我们将一一讲述这5个问题,并用MVC的设计思想来分别解决这些问题。 问题1:基于视图的方案来解决基于行为的需求 我们的网站最终是由用户使用的,用户访问网站肯定会有特定的目的,网站要做的就是通过让用户的交互行为来完成其想要的目的。比如当用户访问一个购物网站时,也许他的交互行为会是这样的: ·购买产品 ·打印发票 这些交互行为是通过按钮点击、右键点击和浏览器URL实现的。由于这些交互都是基于HTTP协议的,所以如果我们能将这些交互行为映射到具体的一些方法上,那么整个架构将会变得简单很多。 但是微软做不到这样,因为它要实现可视化网页编程,所以他们最终选择了基于视图的解决方案。 从上图可以看出,整个请求过程看上去很奇怪: ·用户发起一个HTTP请求,比如HTTPPOST / GET ·IIS服务器将请求映射到视图 ·视图调用页面的生命周期,通过事件驱动,调用合适的交互方法 ·最后将交互的结果展现给终端用户 因为微软一开始就选择了基于视图的设计方案,所以架构本身很难向基于用户交互的设计思想靠拢。换句话说,当用户发出“购买”请求时,先是访问了视图页面“Shopping.aspx”,后台逻辑代码在“Shopping.aspx.cs”中,页面生命周期中会将页面的计算结果返回给用户。 如果利用MVC的思想,都是基于用户交互行为的话,那么请求流程将会是如下所示: 问题2:坏架构的副作用——紧耦合 当选择了一个错误的架构以后,未来将会出现很多难以解决的副作用,在ASP.NETWebForm中就出现了这个问题。尽管behindcode后台代码被分离到不同的文件中,但是ASPX.CS文件和ASPX文件却紧密的联系在一起,这将导致系统的耦合度很高,并且很难解耦合,这是一个很头疼的问题。 简单地说,我们很难将Customer.aspx.cs和CustomerDetailed.aspx简单地剥离开,后台代码已经紧紧地将其捆在一起,而且也很难复用。如果我们可以将请求先通过action,而不通过视图view,action得到的数据再由控制器决定由哪个view展示,那么请求的流程将会是这样的: 所以我们可以很方便地控制最终结果是由移动页面展示还是正常页面展示,如下代码: publicActionResult Index(string DeviceType) { if (viewType == "Mobile") { returnView("MobileView"); } else { returnView("NormalView"); } } 问题3:HTML不是唯一的返回类型 由于视图view和后台代码behindcode紧密耦合在一起,所以默认的返回类型就固定了,都是HTML类型。如果你想改变类型就必须设置Content-type和调用Response.End方法。 如果我们创建一个Action,返回的类型由Action中指定,系统就可以在同一个action中根据不同条件输出不同的返回类型。代码如下: publicActionResult Index(string viewType) { if (viewType == "JSON") { return Json(new Customer(),JsonRequestBehavior.AllowGet); } else { returnView("DisplayCustomer", new Customer()); } } 问题4:视图和数据的灵活组合 Webform是视图优先的架构,所以视图决定了展现的数据,因此视图的扩展性就很差,如果遇到复杂的数据结构,这种方式就显得力不从心了。 但是如果是行为优先的架构的话,当我们触发action时,action可以根据不同的请求选择不同的数据模型和视图结构,如下图: 在MVC中,你可以在不同的view中选择相同的数据模型,比如下面的代码,customerdata数据既可以绑定在DetailCustomer视图中,也可以绑定在Customer视图中。 publicActionResult Index(string ViewName,Customer customerdata) { if (ViewName =="Detailed") { returnView("DetailCustomer",customerdata); } else { returnView("Customer",customerdata); } } 但这在WebForm中实现起来是非常麻烦的。 问题5、将behind code当做普通的类来进行单元测试 behindcode后台代码在WebForm中是一个非常庞大的类,并且不能简单地实例化。要知道WebForm是继承于Page类的,Page类不能直接实例化,因为它有太多的依赖项。 publicpartial class WebForm1 : System.Web.UI.Page { protected void Page_Load(object sender,EventArgs e) { } public void Button1_Click(objectsender, EventArgs e) { Session["SomeSession"] ="Is this set"; } } 为什么我们想要实例化Page类呢?其中一个原因就是可以方便单元测试。比如我要测试一个按钮点击事件,用来检查Session是否设置成功。在WebForm中的代码看起来不是那么舒服: [TestMethod] publicvoid TestMethod1() { WebApplication22.WebForm1 obj = newWebApplication22.WebForm1(); obj.Button1_Click(this, newEventArgs()); } 并且运行时还会抛出一个异常: 在MVC中,这个类变成了一个普通类,我们可以在测试工程中将它实例化,并对类里面的属性方法、Session、ViewBag 、 TempData等进行单元测试。 publicclass HomeController : Controller // this class is simple { public ActionResult Index() { Session["SomeSession"] ="Is this set"; return View("SomeView"); } } 所以是否选择MVC解决方案? 从WebForm架构切换到MVC架构,我们需要做以下几件事情: ·将behindcode中的代码转移到controller类中,并将原来的方法转换成action方法。 ·中间层用数据模型和逻辑接口代替。 ·视图view只用来展现数据和页面布局。 ·DAL层和其他层没有什么变化,因为它和behindcode关系不大。 所以MVC架构中,用户的请求分为下面3个步骤: ·终端用户发送请求,路由器将请求路由到合适的Controller,Controller是逻辑实体和行为Action的集合。 ·Controller将请求映射到特定的Action。 ·Action有两个任务,第一是获取合适的数据,第二是将这些数据和视图View绑定起来。Action创建数据模型,并将数据模型连接到指定View,输出最终的相应结果。

优秀的个人博客,低调大师

swift:入门知识之枚举和结构体

枚举: swift中的枚举有些类似于类这个概念,它有自己的属性,也可以有自己的方法 枚举中的成员有原始值和实际值之分,原始值用来枚举成员的排序次序,默认从0开始 枚举出来的成员值就是实际值 可以通过toRaw和fromRaw函数转换原始值和枚举值 也可以使用字符处或浮点数作为枚举的原始值 枚举: 匹配枚举值和Switch语句(Matching Enumeration Values with a Switch Statement) 具体举例如下: //给扑克牌内容声明一个枚举(A、2、3、4、5、6、7、8、9、10、J、Q、K) enum Rank:Int{ case Ace case Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten case Jack,Queen,King func simpleDescription()->String{ switch self{ case .Ace:return "ace" case .Jack:return "Jack" case .Queen:return "Queen" case .King:return "King" default:return String(self.toRaw()) } } } //创建枚举实例,获取枚举元素的原始值和实际值 let ace = Rank.Jack //获取一个枚举元素 let originValue = ace.toRaw() //该元素的原始值 10 let factvalue = ace.simpleDescription() //该元素的实际值 Jack //将一个原始值转换为实际值 if let origin = Rank.fromRaw(10){ // 10 let fact = origin.simpleDescription() // Jack } //给扑克牌的花色声明一个枚举 enum Suit{ case Spades,Hearts,Diamonds,Clubs func simpleDescription()->String{ switch self{ case .Spades : return "spades" case .Hearts : return "hearts" case .Diamonds:return "diamonds" case .Clubs : return "clubs" } } } //创建枚举实例,获取枚举元素的值 let heart = Suit.Hearts //获取一个枚举元素 let heartsDescription = heart.simpleDescription() //元素的实际值 hearts 结构体: swift中使用struct创建结构体。结构体支持多个与类相同的行为,包括方法和构造器。 一大重要的区别是结构体(以及枚举)代码之间的传递总是用拷贝(值传递),而类则是传递引用(地址传递)。 对于传值调用,是把实参户值传递给形参,此时形参是要被分配空间的,而对形参做的任何操作是不会改变实参的值的; 对于传址调用,是指传递实参的地址,即形参和实参的指针指向同一块内存区域,任何一方对数据做修改,值都会改变。 类和结构体对比 Swift 中类和结构体有很多共同点。共同处在于: 定义属性用于储存值 定义方法用于提供功能 定义下标用于通过下标语法访问值 定义初始化器用于生成初始化值 通过扩展以增加默认实现的功能 符合协议以对某类提供标准功能 //结合上面的枚举的使用,现在声明一个扑克牌结构体,它有扑克牌内容和花色这两个枚举类型的成员变量 struct Card { //成员属性 var rank:Rank var suit:Suit //成员方法 func simpleDescription()->String{ return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } //创建结构体成员实例,并调用成员方法 //传入两个枚举类型的引用创建一个结构体成员变量 let threeOfShapes = Card(rank: .Three, suit: .Spades) //结构体成员变量调用成员方法 let threeOfShapesDescription = threeOfShapes.simpleDescription() //“The 2 of shpades” 总结:结构体和枚举是值类型 值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是其的拷贝。 在之前的章节中,我们已经大量使用了值类型。实际上,在 Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Booleans)、字符串(string)、数组(array)和字典(dictionaries),都是值类型,并且都是以结构体的形式在后台所实现。 在 Swift 中,所有的结构体和枚举都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。 程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式! 分类: Swift开发技术 本文转自当天真遇到现实博客园博客,原文链接: http://www.cnblogs.com/XYQ-208910/p/4905048.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

storm从入门到放弃(一),storm介绍

背景:目前就职于国内最大的IT咨询公司,恰巧又是毕业季,所在部门招了20多个应届毕业生,本人要跟部门新人进行为期一个月的大数据入职培训,特此将整理的文档分享出来。 原文和作者一起讨论:http://www.cnblogs.com/intsmaze/p/7274361.html 微信:intsmaze 避免微信回复重复咨询问题,技术咨询请博客留言。 Storm是一个开源的分布式实时计算系统,可以简单、可靠的处理大量的数据流。Storm支持水平扩展,具有高容错性,保证每个消息都会得到处理。 Storm核心组件 Nimbus:负责资源分配和任务调度,Nimbus对任务的分配信息会落到zookeeper上面的目录下。 Supervisor:负责去zookeeper上的指定目录接受nimbus分配的任务,启动和停止属于自己管理的worker进程。(它是当前物理机器上的管理者)--通过配置文件设置当前supervisor上启动多少个worker。 Worker:运行具体处理组件逻辑的进程。Worker运行的任务类型只有两种,一种是Spout任务,一种是Bolt任务。 Task:worker中每一个spout/bolt的线程称为一个task.在storm0.8之后,task不再与物理线程对应,不同spout/bolt的task可能会共享一个物理线程,该线程称为executor。 Storm一些概念 Topologies : 拓扑,也俗称一个任务。(可以理解为一个storm集群) Spouts : 拓扑的消息源。 Bolts : 拓扑的处理逻辑单元。(一个Bolt类会在集群里面很多机器上并发执行) (Spouts,Bolts可以理解为storm中的两个组件) tuple:消息元组(是在Spouts,Bolts中传递数据的一种封装的格式) Streams : 流 Stream groupings :流的分组策略 Tasks : 任务处理单元 Executor :工作线程 Workers :工作进程 Configuration : topology的配置 Storm中的Workers 一个topology可能会在一个或者多个worker(工作进程)里面执行;一个进程里面会启动多个Executor :工作线程。 每个worker是一个物理JVM并且执行整个topology的一部分;在一个物理节点上可以运行一个或多个独立的JVM 进程。一个Topology可以包含一个或多个worker(并行的跑在不同的物理机上), 所以worker process就是执行一个topology的子集, 并且worker只能对应于一个topology。比如,对于并行度是300的topology来说,如果我们使用50个工作进程来执行,那么每个工作进程会处理其中的6个tasks; Storm会尽量均匀的工作分配给所有的worker;一个Executor:工作线程里面可以运行多个相同的task实例。 Storm中的Tasks 每一个spout和bolt会被当作很多task在整个集群里执行;每一个executor对应到一个线程,在这个线程上运行多个task;stream grouping则是定义怎么从一堆task发射tuple到另外一堆task;可以调用TopologyBuilder类的setSpout和setBolt来设置并行度(也就是有多少个task) Executors (threads) 在一个worker JVM进程中运行着多个Java线程。一个executor线程可以执行一个或多个tasks。但一般默认每个executor只执行一个task。(开发中也不建议一个executor里面执行多个task.)一个worker可以包含一个或多个executor, 每个component (spout或bolt)至少对应于一个executor, 所以可以说executor执行一个compenent的子集, 同时一个executor只能对应于一个component。 Storm中的Stream 消息流stream是storm里的关键抽象;一个消息流是一个没有边界的tuple序列, 而这些tuple序列会以一种分布式的方式并行地创建和处理;通过对stream中tuple序列中每个字段命名来定义stream。 在默认的情况下,tuple的字段类型可以是:integer,long,short, byte,string,double,float,boolean和byte array;可以自定义类型(只要实现相应的序列化器)。 数据从一个节点传到另一个节点,数据是要被序列化的,但在storm中,数据序列化之前,消息必须按照一定的格式传递,这个格式就是一个一个的消息元组。消息元组是源源不断的发送的,这个元组就类似一个list,里面有若干个字段。 Storm编程模型 有向无环图 public class RandomSentenceSpout extends BaseRichSpout { public void nextTuple() { collector.emit(new Values("+ - * % /")); Utils.sleep(50000); } ...... } public class SplitSentenceBolt extends BaseBasicBolt { public void execute(Tuple input, BasicOutputCollector collector) { String sentence = (String)input.getValueByField("intsmaze"); System.out.println(Thread.currentThread().getId()+" "+sentence); } ...... } public class TwoBolt extends BaseBasicBolt { public void execute(Tuple input, BasicOutputCollector collector) { String sentence = (String)input.getValueByField("intsmaze"); System.out.println(Thread.currentThread().getId()+" "+sentence); } ...... } public class WordCountTopologyMain { public static void main(String[] args) throws Exception { TopologyBuilder builder = new TopologyBuilder(); builder.setSpout("spout1", new RandomSentenceSpout(),1); builder.setBolt("two", new TwoBolt(),1).shuffleGrouping("spout1"); builder.setBolt("split1", new SplitSentenceBolt(),2).shuffleGrouping("spout1"); Config conf = new Config(); conf.setDebug(false); conf.setMaxTaskParallelism(3); LocalCluster cluster = new LocalCluster(); cluster.submitTopology("word-count", conf, builder.createTopology()); } } } 可以发现spout每隔一段时间间隔发一份数据,这份数据会被两个bolt同时接收,而不是说这次A bolt接收下次B bolt接收。 同一个bolt业务逻辑如果设置了并行度,他们才会根据分组策略依次接收上游发来的消息。 ----------------84 + - * % / 这个是tow bolt接收 ----------------78 + - * % / 这个是split1 bolt 中78线程接收的 ----------------80 + - * % / 这个是split1 bolt中线程80接收的。 ----------------84 + - * % / ----------------78 + - * % / ----------------84 + - * % / Storm7种stream grouping Shuffle Grouping: 随机分组,随机派发stream里面的tuple,保证每个bolt接收到的tuple数目大致相同。 Fields Grouping:按字段分组,比如按userid来分组,具有同样userid的tuple会被分到相同的Bolts里的一个task,而不同的userid则会被分配到不同的bolts里的task。 All Grouping:广播发送,对于每一个tuple,所有的bolts都会收到。 Global Grouping:全局分组, 这个tuple被分配到storm中的一个bolt的其中一个task。再具体一点就是分配给id值最低的那个task。 Non Grouping:不分组,这stream grouping个分组的意思是说stream不关心到底谁会收到它的tuple。目前这种分组和Shuffle grouping是一样的效果,有一点不同的是storm会把这个bolt放到这个bolt的订阅者同一个线程里面去执行。 Direct Grouping: 直接分组, 这是一种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发射。消息处理者可以通过TopologyContext来获取处理它的消息的task的id (OutputCollector.emit方法也会返回task的id)。 Local or shuffle grouping:如果目标bolt有一个或者多个task在同一个工作进程中,tuple将会被随机发生给这些tasks。否则,和普通的Shuffle Grouping行为一致。 conf.setNumWorkers(4) 表示设置了4个worker来执行整个topology的所有组件 builder.setBolt("boltA-intsmaze",new BoltA(), 4) ---->指明 boltA组件的线程数excutors总共有4个 builder.setBolt("boltB-intsmaze",new BoltB(), 4) ---->指明 boltB组件的线程数excutors总共有4个 builder.setSpout("randomSpout-intsmaze",new RandomSpout(), 2) ---->指明randomSpout组件的线程数excutors总共有2个 -----意味着整个topology中执行所有组件的总线程数为4+4+2=10个 ----worker数量是4个,有可能会出现这样的负载情况,worker-1有2个线程,worker-2有2个线程,worker-3有3个线程,worker-4有3个线程 如果指定某个组件的具体task并发实例数 builder.setSpout("randomspout-intsmaze", new RandomWordSpout(), 4).setNumTasks(8); ----意味着对于这个组件的执行线程excutor来说,一个excutor将执行8/4=2个task,默认情况一个线程执行一个task. 作者: intsmaze(刘洋) 出处: http://www.cnblogs.com/intsmaze/ 老铁,你的--->推荐,--->关注,--->评论--->是我继续写作的动力。 微信公众号号:Apache技术研究院 由于博主能力有限,文中可能存在描述不正确,欢迎指正、补充! 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

优秀的个人博客,低调大师

开源人脸识别seetaface入门教程(一)

简述 seetaface由中科院计算所山世光研究员带领的人脸识别研究组研发。代码基于C++实现,不依赖第三方库。然而,目前开源的代码,是在windows vs上编译的,对于我们这帮mac/linux用户来说,用起来还是挺麻烦的。经过这几天的学习,对seetaface总算有了全面的了解。下面,听我娓娓道来。 注意:本文章不涉及代码逻辑和原理,只是教大家如何使用seetaface做人脸识别。 引擎 FaceDetection 人脸识别模块,用于识别出照片中的人脸,染回每个人脸的坐标和人脸总数。 FaceAlignment 特征点识别模块,主要识别两个嘴角、鼻子、两个眼睛五个点的坐标。测试下来,发现图片模糊时,识别不准。 FaceIdentification 人脸比较模块,根据官方的说法,先提取特征值,然后比较。给出的测试程序是seetaface提取人脸的特征值和caffe训练库里的人脸做对比。 以下教程都是在MacOSX编译运行通过。使用cmake和make编译 以下的编译方法是把FaceDetect测试程序也编译了,而测试程序是依赖opencv的,所以,在这之前,确认opencv是否安装 人脸识别教程 编译 由于代码是在windows平台编译的,所以,这地方要做些修改。 进入FaceDetection目录 修改include/common.h,修改38行 #ifdefSEETA_EXPORTS #defineSEETA_API__declspec(dllexport) #else #defineSEETA_API__declspec(dllimport) #endif 为 #ifdefined_WIN32 #ifdefSEETA_EXPORTS #defineSEETA_API__declspec(dllexport) #else #defineSEETA_API__declspec(dllimport) #endif #else #defineSEETA_API #endif 修改include/feat/surf_feature_map.h文件,在前面加上#include <cstring> 修改include/util/image_pyramid.h文件,在前面加上#include <cstring> 修改src/feat/surf_feature_map.cpp文件,在前面加上#include <cmath> 增加CMakeLists.txt,内容如下: cmake_minimum_required(VERSION3.3) project(seeta_facedet_lib) option(BUILD_EXAMPLES"SettoONtobuildexamples"ON) option(USE_OPENMP"SettoONtobuilduseopenmp"ON) set(CMAKE_CXX_STANDARD11) set(CMAKE_CXX_STANDARD_REQUIREDON) message(STATUS"C++11supporthasbeenenabledbydefault.") set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS}-msse4.1") if(USE_OPENMP) find_package(OpenMPQUIET) if(OpenMP_FOUND) message(STATUS"UseOpenMP") add_definitions(-DUSE_OPENMP) set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS}${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS}${OpenMP_CXX_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS"${CMAKE_EXE_LINKER_FLAGS}${OpenMP_EXE_LINKER_FLAGS}") endif() endif() include_directories(include) set(src_files src/util/nms.cpp src/util/image_pyramid.cpp src/io/lab_boost_model_reader.cpp src/io/surf_mlp_model_reader.cpp src/feat/lab_feature_map.cpp src/feat/surf_feature_map.cpp src/classifier/lab_boosted_classifier.cpp src/classifier/mlp.cpp src/classifier/surf_mlp.cpp src/face_detection.cpp src/fust.cpp ) add_library(face_detectSHARED${src_files}) set(facedet_required_libsface_detect) if(BUILD_EXAMPLES) message(STATUS"Buildwithexamples.") find_package(OpenCV) if(NOTOpenCV_FOUND) message(WARNING"OpenCVnotfound.Testwillnotbebuilt.") else() include_directories(${OpenCV_INCLUDE_DIRS}) list(APPENDfacedet_required_libs${OpenCV_LIBS}) add_executable(facedet_testsrc/test/facedetection_test.cpp) target_link_libraries(facedet_test${facedet_required_libs}) endif() endif() 建立build目录,mkdir build 编译,cd build && cmake .. && make 当前目录下生成可执行文件 运行 执行完make命令以后,当前的目录下会生成一个可执行文件facedet_test 由于默认的程序读取的是当前路径下的test_image.jpg和seeta_fd_frontal_v1.0.bin,test_image.jpg是人脸图片,seeta_fd_frontal_v1.0是识别的引擎。 确保以上的两个文件在当前路径下存在了,既可以./facedet_test运行了。 你可以修改位于src/test目录下的文件,来达到自己的目的。 使用 我们可以参考src/test/facedetection_test.cpp这个测试程序,来达到我们人脸识别的目的。 头文件 #include"opencv2/highgui/highgui.hpp" #include"opencv2/imgproc/imgproc.hpp" #include"face_detection.h" opencv头文件主要用来加载图像,face_detection.h是人脸识别的主要程序。 加载人脸识别引擎 seeta::FaceDetectiondetector(‘seeta_fd_frontal_v1.0’); 设置最小人脸大小 detector.SetMinFaceSize(40); 这个根据实际情况调整,图片中,人脸越大,这个值也越大,因为这个值越小,人脸识别速度越慢。 识别图片中的人脸 std::vector<seeta::FaceInfo>faces=detector.Detect(img_data); 在这之前,需要对图片进行处理,这里略过 输出人脸识别的结果 for(int32_ti=0;i<num_face;i++){ face_rect.x=faces[i].bbox.x; face_rect.y=faces[i].bbox.y; face_rect.width=faces[i].bbox.width; face_rect.height=faces[i].bbox.height; cv::rectangle(img,face_rect,CV_RGB(0,0,255),4,8,0); } s[i].bbox.x;faces[i].bbox.y;是人脸的左上角坐标。faces[i].bbox.width;faces[i].bbox.height;是人脸的长和宽。 结语 seetaface的确是个很好用的人脸识别库,调用、编译都很简单,但是由于文档的缺少,所以刚开始看的时候,会比较乱,不知道如何下手。本片文章主要介绍了FaceDetect的使用,接下来我会讲解如何识别人脸的特征点,也就是嘴、鼻子、眼。敬请期待。 作者:xiaochao 来源:51CTO

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册