当前位置: 首页 > 编程日记 > 正文

[ASP.NET MVC 小牛之路]10 - Controller 和 Action (2)

继上一篇文章之后,本文将介绍 Controller 和 Action 的一些较高级特性,包括 Controller Factory、Action Invoker 和异步 Controller 等内容。

本文目录

开篇:示例准备

文章开始之前,我们先来了解一下一个请求的发出到Action方法处理后返回结果的流程,请试着理解下图:

本文的重点是 controller factory 和 action invoker。顾名思义,controller factory 的作用是创建为请求提供服务的Controller实例;action invoker 的作用是寻找并调用Action方法。MVC框架为这两者都提供了默认的实现,我们也可以对其进行自定义。

首先我们为本文要演示的示例做一些准备,把暂时想到的要用的 View、Controller 和 Action 都创建好。新建一个空的MVC应用程序,在Models文件夹中添加一个名为 Result 的Model,代码如下:

namespace MvcApplication2.Models {public class Result {public string ControllerName { get; set; }public string ActionName { get; set; }}
}

在 /Views/Shared 文件夹下添加一个名为 Result.cshtml 的视图(不使用Layout),添加代码如下:

...
<body><div>Controller: @Model.ControllerName</div> <div>Action: @Model.ActionName</div> 
</body>

本文的所有Action方法将都使用这同一个View,目的是显示被执行的Controller名称和Action名称。

然后我们创建一个名为Product的Controller,代码如下:

public class ProductController : Controller {public ViewResult Index() {return View("Result", new Result {ControllerName = "Product",ActionName = "Index"});}public ViewResult List() {return View("Result", new Result {ControllerName = "Product",ActionName = "List"});}
}

继续添加一个名为Customer的Controller,代码如下:

public class CustomerController : Controller {public ViewResult Index() {return View("Result", new Result {ControllerName = "Customer",ActionName = "Index"});}public ViewResult List() {return View("Result", new Result {ControllerName = "Customer",ActionName = "List"});}
}

准备工作做好了,开始进入正题吧。

自定义 Controller Factory

Controller Factory,顾名思义,它就是创建 controller 实例的地方。想更好的理解Controller Factory是如何工作的,最好的方法就是自己去实现一个自定义的。当然,在实际的项目中我们很少会去自己实现,一般使用内置的就足够。自定义一个Controller Factory需要实现 IControllerFactory 接口,这个接口的定义如下:

using System.Web.Routing; 
using System.Web.SessionState;namespace System.Web.Mvc { public interface IControllerFactory { IController CreateController(RequestContext requestContext, string controllerName); SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName); void ReleaseController(IController controller); } 
}

我们创建一个名为 Infrastructure 文件夹,在这个文件夹中创建一个名为 CustomControllerFactory 的类文件,在这个类中我们将简单的实现 IControllerFactory 接口的每个方法,代码如下:

using System;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
using MvcApplication2.Controllers;namespace MvcApplication2.Infrastructure {public class CustomControllerFactory : IControllerFactory {public IController CreateController(RequestContext requestContext, string controllerName) {Type targetType = null;switch (controllerName) {case "Product":targetType = typeof(ProductController);break;case "Customer":targetType = typeof(CustomerController);break;default:requestContext.RouteData.Values["controller"] = "Product";targetType = typeof(ProductController);break;}return targetType == null ? null : (IController)DependencyResolver.Current.GetService(targetType);}public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName) {return SessionStateBehavior.Default;}public void ReleaseController(IController controller) {IDisposable disposable = controller as IDisposable;if (disposable != null) {disposable.Dispose();}}}
}

先来分析一下这个类。

这里最重要的方法是 CreateController,当MVC框架需要一个 Controller 来处理请求时调用该方法。它有两个参数,一个是 RequestContext 对象,通过它我们可以得到请求相关的信息;第二个参数是一个string类型的controller名称,它的值来自于URL。这里我们只创建了两个Controller,所以我们在 CreateController 方法中进行了硬编码(写死了controller的名称),CreateController 方法的目的是创建Controller实例。

在自定义的Cotroller Factory中,我们可以任意改变系统默认的行为,比如switch语句中的default节点:

requestContext.RouteData.Values["controller"] = "Product";

它将路由的controller值改为Product,使得执行的cotroller并不是用户所请求的controller。

在本系列的 [ASP.NET MVC 小牛之路]05 - 使用 Ninject 文章中也讲了一个用 Ninject 创建Controller Factory的例子,使用的是 ninjectKernel.Get(controllerType) 方法来创建Controller实例。这里我们使用 MVC 框架提供的 DependencyResolver 类来创建:

return targetType == null ? null : (IController)DependencyResolver.Current.GetService(targetType);

静态的 DependencyResolver.Current 属性返回一个 IDependencyResolver 接口的实现,这个实现中定义了 GetService 方法,它根据 System.Type 对象(targetType)参数自动为我们创建 targetType 实例,和使用Ninject类似。

最后来看看实现 IControllerFactory 接口的另外两个方法。

GetControllerSessionBehavior 方法,告诉MVC框架是否保留Session数据,这点放在文章后面讲。

ReleaseController 方法,当controller对象不再需要时被调用,这里我们判断controller对象是否实现了IDisposable接口,实现了则调用 Dispose 方法来释放资源。

CustomControllerFactory 类分析完了。和 [ASP.NET MVC 小牛之路]05 - 使用 Ninject 讲的示例一样,要使用自定义的Controller Factory还需要在 Global.asax.cs 文件的 Application_Start 方法中对自定义的 CustomControllerFactory 类进注册,如下:

protected void Application_Start() {...ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
}

运行程序,应用程序根据路由设置的默认值显示如下:

你可以定位到任意 /xxx/xxx 格式的URL来验证我们自定的 Controller Factory 的工作。

使用内置的 Controller Factory

为了帮助理解Controller Factory是如何工作,我们通过实现IControllerFactory接口自定义了一个Controller Factory。在实际的项目中,我们一般不会这么做,大多数情况我们使用内置的Controller Factory,叫 DefaultControllerFactory。当它从路由系统接收到一个请求后,从路由实例中解析出 controller 的名称,然后根据名称找到 controller 类,这个类必须满足下面几个标准:

  • 必须是public。
  • 必须是具体的类(非抽象类)。
  • 没有泛型参数。
  • 类的名称必须以Controller结尾。
  • 类必须(间接或直接)实现IController接口。

DefaultControllerFactory类维护了一个满足以上标准的类的列表,这样当每次接收到一个请求时不需要再去搜索一遍。当它找到了合适的 controller 类,则使用Controller Activator(一会介绍)来创建Controller 类的实例。它内部是通过 DependencyResolver 类进行依赖解析创建 controller 实例的,和使用Ninject是类似的原理。

你可以通过继承 DefaultControllerFactory 类重写其中默认的方法来自定义创建 controller 的过程,下面是三个可以被重写的方法:

  • GetControllerType,返回Type类型,为请求匹配对应的 controller 类,用上面定义的标准来筛选 controller 类也是在这里执行的。
  • GetControllerInstance,返回是IController类型,作用是根据指定 controller 的类型创建类型的实例。
  • CreateController 方法,返回是 IController 类型,它是 IControllerFactory 接口的 CreateController 方法的实现。默认情况下,它调用 GetControllerType 方法来决定哪个类需要被实例化,然后把controller 类型传递给GetControllerInstance。

重写 GetControllerInstance 方法,可以实现对创建 controller 实例的过程进行控制,最常见的是进行依赖注入。

在本系列的 [ASP.NET MVC 小牛之路]05 - 使用 Ninject 文章中的示例就是一个对 GetControllerInstance 方法进行重写的完整示例,在这就不重复演示了。

现在我们知道 DefaultControllerFactory 通过 GetControllerType 方法拿到 controller 的类型后,它把类型传递给 GetControllerInstance 方法以获取 controller 的实例。那么,GetControllerInstance 又是如何来获取实例的呢?这就需要讲到另外一个 controller 中的角色了,它就是下面讲的:Controller Activator。

Controller 的激活

当 DefaultControllerFactory 类接收到一个 controller 实例的请求时,在 DefaultControllerFactory 类内部通过 GetControllerType 方法来获得 controller 的类型,然后把这个类型传递给 GetControllerInstance 方法以获得 controller 的实例。

所以在 GetControllerInstance  方法中就需要有某个东西来创建 controller 实例,这个创建的过程就是 controller 被激活的过程。

默认情况下 MVC 使用 DefaultControllerActivator 类来做 controller 的激活工作,它实现了 IControllerActivator 接口,该接口定义如下:

public interface IControllerActivator { IController Create(RequestContext requestContext, Type controllerType); 
}

该接口仅含有一个 Create 方法,RequestContext 对象参数用来获取请求相关的信息,Type 类型参数指定了要被实例化的类型。DefaultControllerActivator 类中整个 controller 的激活过程就在它的 Create 方法里面。下面我们通过实现这个接口来自定义一个简单的 Controller Activator:

public class CustomControllerActivator : IControllerActivator {public IController Create(RequestContext requestContext, Type controllerType) {if (controllerType == typeof(ProductController)) {controllerType = typeof(CustomerController);}return (IController)DependencyResolver.Current.GetService(controllerType);}
}

这个 CustomControllerActivator 非常简单,如果请求的是 ProductController 则我们给它创建 CustomerController 的实例。为了使用这个自定的 Activator,需要在 Global.asax 文件中的 Application_Start 方法中注册 Controller Factory 时给 Factory 的构造函数传递我们的这个 Activator 的实例,如下:

protected void Application_Start() { ...ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new CustomControllerActivator())); 
} 

运行程序,把URL定位到 /Product ,本来路由将指定到 Product controller, 然后 DefaultControllerFactory 类将请求 Activator 创建一个 ProductController 实例。但我们注册了自义的 Controller Activator,在这个自定义的 Activator 创建 Controller 实例的的时候,我们做了一个“手脚”,改变了这种默认行为。当请求创建 ProductController 实例时,我们给它创建了CustomerController 的实例。结果如下:

其实更多的时候,我们自定义 controller 的激活机制是为了引入IoC,和 [ASP.NET MVC 小牛之路]05 - 使用 Ninject 讲的通过继承 DefaultControllerFactory 引入 IoC 是一个道理。

自定义 Action Invoker

当 Controller Factory 创建好了一个类的实例后,MVC框架则需要一种方式来调用这个实例的 action 方法。如果创建的 controller 是继承 Controller 抽象类的,那么则是由 Action Invoker 来完成调用 action 方法的任务,MVC 默认使用的是 ControllerActionInvoker 类。如果是直接继承 IController 接口的 controller,那么就需要手动来调用 action 方法,见上一篇 [ASP.NET MVC 小牛之路]09 - Controller 和 Action (1) 。下面我们通过自定义一个 Action Invoker 来了解一下 Action Invoker 的运行机制。

创建一个自定义的 Action Invoker 需要实现 IActionInvoker 接口,该接口的定义如下:

public interface IActionInvoker { bool InvokeAction(ControllerContext controllerContext, string actionName); 
} 

这个接口只有一个 InvokeAction 方法。ControllerContext 对象参数包含了调用该方法的controller的信息,string类型的参数是要调用的Action方法的名称,这个名称来源于路由系统。返回值为bool类型,当actoin方法被找到并被调用时返回true,否则返回false。

下面是实现了IActionInvoker接口的 CustomActionInvoker 类:

using System.Web.Mvc;namespace MvcApplication2.Infrastructure {public class CustomActionInvoker : IActionInvoker {public bool InvokeAction(ControllerContext controllerContext, string actionName) {if (actionName == "Index") {controllerContext.HttpContext.Response.Write("This is output from the Index action");return true;}else {return false;}}}
}

这个 CustomActionInvoker 不需要关心实际被调用的Action方法。如果请求的是Index Action,这个 Invoker 通过 Response 直接输出一个消息,如果不是请Index Action,则会引发一个404-未找到错误。

决定Controller使用哪个Action Invoker是由 Controller 中的 Controller.ActionInvoker 属性来决定的,由它来告诉MVC当前的 controller 将使用哪个 Action Invoker 来调用 Action 方法。如下我们创建一个ActionInvokerController,并在它的构造函数中指定了 Action Invoker 为我们自定义的 Action Invoker:

namespace MvcApplication2.Controllers {public class ActionInvokerController : Controller {public ActionInvokerController() {this.ActionInvoker = new CustomActionInvoker();}}
}

这个 controller 中没有 Action 方法,它依靠 CustomActionInvoker 来处理请求。运行程序,将URL定位到 /ActionInvoker/Index 可见如下结果:

如果将URL定位到 ActionInvoker 下的其他Action,则会返回一个404的错误页面。

我们不推荐去实现自己的Action Invoker。首先内置的Action Invoker提供了一些非常有用的特性;其次是缺乏可扩展性和对View的支持等。这里只是为了演示和理解MVC框架处理请求过程的细节。

使用内置的 Action Invoker

通过自定义 Action Invoker,我们知道了MVC调用 Action 方法的机制。我们创建一个继承自 Controller 抽象类的 controller,如果不指定Controller.ActionInvoker,那么MVC会使用内置默认的Action Invoker,它是 ControllerActionInvoker 类。它的工作是把请求匹配到对应的 Action 方法并调用之,简单说就是寻找和调用 Action 方法。

为了让内置的 Action Invoker 能匹配到 Action 方法,Action方法必须满足下面的标准:

  • 必须是公共的(public)。
  • 不能是静态的(static)。
  • 不能是System.Web.Mvc.Controller中存在的方法,或其他基类中的方法。如方法不能是 ToString 和 GetHashCode 等。
  • 不能是一个特殊的名称。所谓特殊的名称是方法名称不能和构造函数、属性或者事件等的名称相同。

注意,Action方法也不能带有泛型,如MyMethod<T>(),虽然 Action Invoker 能匹配到,但会抛出异常。

内置的 Action Invoker 给我们提供了很多实用的特性,给开发带来很大便利,下面两节内容可以说明这一点。

给 Action 方法定义别名

默认情况下,内置的Action Invoker (ControllerActionInvoker)寻找的是和请求的 action 名称相同的 action 方法。比如路由系统提供的 action 值是 Index,那么 ControllerActionInvoker 将寻找一个名为 Index 的方法,如果找到了,它就用这个方法来处理请求。ControllerActionInvoker 允许我们对此行为进行调整,即可以通过使用 ActionName 特性对 action 使用别名,如下对 CustomerController 的 List action 方法使用 ActionName 特性:

public class CustomerController : Controller {...[ActionName("Enumerate")]public ViewResult List() {return View("Result", new Result {ControllerName = "Customer",ActionName = "List"});}
}

当请求 Enumerate Action 时,将会使用 List 方法来处理请求。下面是请求 /Customer/Enumerate 的结果:

这时候对 /Customer/List 的请求则会无效,报“找不到资源”的错误,如下:

使用 Action 方法别名有两个好处:一是可以使用非法的C#方法名来作为请求的 action 名,如 [ActionName("User-Registration")]。二是,如果你有两个功能不同的方法,有相同的参数相同的名称,但针对不同的HTTP请求(一个使用 [HttpGet],另一个使用 [HttpPost]),你可以给这两个方法不同的方法名,然后使用 [ActionName] 来指定相同的 action 请求名称。

Action 方法选择器

我们经常会在 controller 中对多个 action 方法使用同一个方法名。在这种情况下,我们就需要告诉 MVC 怎样在相同的方法名中选择正确的 action 方法来处理请求。这个机制称为 Action 方法选择,它在基于识别方法名称的基础上,允许通过请求的类型来选择 action 方法。MVC 框架可使用C#特性来做到这一点,所以这种作用的特性可以称为 Action 方法选择器。

内置 Action 方法选择器

MVC提供了几种内置的特性来支持 Action 方法选择,它包括HttpGet、HttpPost、HttpPut 和 NonAction 等。这些选择器从名字上很容易理解什么意思,这里就不解释了。下面举个 NonAction 的例子。在 CustomerController 中添加一个 MyAction 方法,然后应用 [NonAction] 特性,如下:

public class CustomerController : Controller {...[NonAction]public ActionResult MyAction() {return View();}
}

使用 [NonAction] 后,方法将不会被识别为 action 方法,如下是请求 /Customer/MyAction 的结果:

当然我们也可以通过把方法声明为 private 来告诉MVC它不是一个 action 方法。

自定义 Action 方法选择器

除了使用内置的Action方法选择器外,我们也可以自定义。所有的 action 选择器都继承自 ActionMethodSelectorAttribute 类,这个类的定义如下:

using System.Reflection; namespace System.Web.Mvc { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public abstract class ActionMethodSelectorAttribute : Attribute { public abstract bool IsValidForRequest(ControllerContext controllerContext,  MethodInfo methodInfo); } 
}

它是一个抽象类,只有一个抽象方法:IsValidForRequest。通过重写这个方法,可以判断某个请求是否允许调用 Action 方法。

我们来考虑这样一种情况:同一个URL请求,在本地和远程请求的是不同的 action (如对于本地则绕过权限验证可能需要这么做)。那么自定义一个本地的 Action 选择器会是一个不错的选择。下面我们来实现这样一个功能的 Action 选择器:

using System.Reflection;
using System.Web.Mvc;namespace MvcApplication2.Infrastructure {public class LocalAttribute : ActionMethodSelectorAttribute {public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {return controllerContext.HttpContext.Request.IsLocal;}} 
}

修改 CustomerController,添加一个LocalIndex 方法,并对它应用 “Index”别名,代码如下:

public class CustomerController : Controller {public ViewResult Index() {return View("Result", new Result {ControllerName = "Customer",ActionName = "Index"});}[ActionName("Index")]public ViewResult LocalIndex() {return View("Result", new Result {ControllerName = "Customer",ActionName = "LocalIndex"});}...          
}

这时如果请求 /Customer/Index,这两个 action 方法都会被匹配到而引发歧义问题,程序将会报错:

这时候我们再对 LocalIndex 应用我们自定义的 Local 选择器:

...
[Local]
[ActionName("Index")]
public ViewResult LocalIndex() {return View("Result", new Result {ControllerName = "Customer",ActionName = "Index"});
}
...

程序在本地运行的时候则会匹配到 LocalIndex action方法,结果如下:

通过这个例子我们也发现,定义了选择器特性的Action方法被匹配的优先级要高于没有定义选择器特性的Action方法。

异步 Controller

对于 ASP.NET 的工作平台 IIS,它维护了一个.NET线程池用来处理客户端请求。这个线程池称为工作线程池(worker thread pool),其中的线程称为工作线程(worker threads)。当接收到一个客户端请求,一个工作线程从工作线程池中被唤醒并处理接收到的请求。当请求被处理完了后,工作线程又被这个线程池回收。这种线程程池的机制对ASP.NET应用程序有如下两个好处:

  • 通过线程的重复利用,避免了每次接收到一个新的请求就创建一个新的线程。
  • 线程池维护的线程数是固定的,这样线程不会被无限制地创建,减少了服务器崩溃的风险。

一个请求是对应一个工作线程,如果MVC中的action对请求处理的时间很短暂,那么工作线程很快就会被线程池收回以备重用。但如果执行action的工作线程需要调用其他服务(如调用远程的服务,数据的导入导出),这个服务可能需要花很长时间来完成任务,那么这个工作线程将会一直等待下去,直到调用的服务返回才继续工作。这个工作线程在等待的过程中什么也没做,资源浪费了。设想一下,如果这样的action一多,所有的工作线程都处于等待状态,大家都没事做,而新的请求来了又没人理,这样就陷入了尴尬境地。

解决这个问题需要使用异步(asynchronous) Controller,异步Controller允许工作线程在等待(await)的时候去处理别的请求,这样做减少了资源浪费,有效提高了服务器的性能。

使用异步 Controller 需要用到.NET 4.5的新特性:异步方法。异步方法有两个新的关键字:await 和 async。这个新知识点朋友们自己去网上找找资料看吧,这里就不讲了,我们把重点放在MVC中的异步 Controller 上。

在Models文件夹中添加一个 RemoteService 类,代码如下:

using System.Threading;
using System.Threading.Tasks;namespace MvcApplication2.Models {public class RemoteService {public async Task<string> GetRemoteDataAsync() {return await Task<string>.Factory.StartNew(() => {Thread.Sleep(2000);return "Hello from the other side of the world";});}}
}

然后创建一个名为 RemoteData 的 Controller,让它继承自 AsyncController 类,代码如下:

using System.Web.Mvc;
using MvcApplication2.Models;
using System.Threading.Tasks;namespace MvcApplication2.Controllers {public class RemoteDataController : AsyncController {public async Task<ActionResult> Data() {string data = await new RemoteService().GetRemoteDataAsync();Response.Write(data);return View("Result", new Result {ControllerName = "RemoteData",ActionName = "Data"});}}
}

运行程序,URL 定位到 /RemoteData/Data,2秒后将显示如下结果:

当请求 /RemoteData/Data 时,Data 方法开始执行。当执行到下面代码调用远程服务时:

string data = await new RemoteService().GetRemoteDataAsync();

工作线程开始处于等待状态,在等待过程中它可能被派去处理新的客户端请求。当远程服务返回结果了,工作线程再回来处理后面的代码。这种异步机制避免了工作线程处于闲等状态,尽可能的利用已被激活的线程资源,对提高MVC应用程序性能是很有帮助的。、

评论精选

提问 by 卤鸽:

IActionInvoker是在Controller.Excute方法中被调用,主要是查询具体的Action 处理方法,其实整个请求的过程都是从MvcHandler进行开始的。这是我的理解。不知正确否?

回答 by Liam Wang

是这么个意思,但不太严谨。确切一点说,Excute 方法是(自定义或默认的)ActionInvoker 的入口函数。 ActionInvoker 必须实现 IActionInvoker 接口来查找和调用 Action 方法。本文没有介绍 MvcHandler 的知识。MvcHandler 是处理Controller的开始,但在MvcHandler 之前还有一个MvcRouteHandler,当请求经过路由解析后,MvcRouteHandler 实例会生成一个 MvcHandler 实例,并把请求交给它。MvcHandler 会从Controller 工厂中获取一个 Controller 实例,然后由 Controller 来具体地处理请求。


PS:这篇文章写到一半便在草稿箱中沉睡了一个多月,10月份20多天都在内蒙出差,回来都没什么兴致继续写下去。希望朋友们多多支持,让我有动力把这个系列写完。

转载于:https://www.cnblogs.com/willick/p/3331513.html

相关文章:

Linux下遍历指定目录的C++实现

之前在 https://blog.csdn.net/fengbingchun/article/details/51474728 给出了在Windows遍历指定文件夹的C实现&#xff0c;这里给出在Linux下遍历目录的实现&#xff0c;Windows和Linux下的实现都是参考了OpenCV 2.x中的实现&#xff0c;OpenCV中的用法可参考https://blog.csd…

要活102年,阿里凭借的是什么?

由浅到深、由轻到重、由拥抱到创新&#xff0c;看似“风平浪静”的历史背后&#xff0c;中国互联网江湖的发展实则“波涛汹涌”。对于身处核心位置的科技巨头阿里巴巴而言&#xff0c;将如何更好地去实现“希望活 102 年”的愿景&#xff1f;凭借的究竟又是什么&#xff1f;作者…

Go基础知识学习(6) 接口

2019独角兽企业重金招聘Python工程师标准>>> Golang接口定义使用interface来声明&#xff0c;它相对于其他语言最大的特定就是接口定义和实现的关联性仅仅依赖接口的名字和声明&#xff0c;无需显式声明。 接口定义和实现 在下面这个例子中&#xff0c;定义了两个自…

多模态数据+知识图谱,这次你的疑难杂症有解了!

数据是AI的基础&#xff0c;不同行业领域的数据来源广泛、形式多样&#xff0c;其每一种来源或形式都可以看作是一种模态&#xff0c;例如视频、图片、语音以及工业场景下的传感数据&#xff0c;红外、声谱等。多模态数据的语义理解与知识表示让智能体能更深入地感知、理解真实…

Linux下通过gettimeofday函数获取程序段执行时间

在Linux下计算某个程序段执行的时间一般使用gettimeofday函数&#xff0c;此函数的声明在sys/time.h文件中。此函数接收两个结构体参数&#xff0c;分别为timeval、timezone.两个结构体的声明如下&#xff1a;struct timeval {time_t tv_sec; /* seconds */long tv_usec; /* mi…

matlab练习程序(Log Polar变换)

Log Polar就是所谓的极坐标变换&#xff0c;通过变换能将笛卡尔坐标系中的图像映射到极坐标系中。 确切的来说我这里不算是Log Polar&#xff0c;因为Log Polar是将图像从&#xff08;x,y&#xff09;映射到(log(r),theta)&#xff0c;而我是将图像从&#xff08;x,y&#xff0…

SiteMapPath基本用法

1、添加一个网站地图项 Web.sitemap项 2、在 Web.sitemap项的写法如下&#xff1a; <?xml version"1.0" encoding"utf-8"?><siteMap xmlns"http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"><siteMapNode url"defa…

closurescallbacks

引用文章原文地址&#xff1a;&#xff08;声明&#xff1a;文章只为自己总结知识&#xff0c;内容东拼西凑&#xff0c;版权归以下作者所有。&#xff09; 1. Wikipedia: callback(computer science) 2. Implement callback routines in Java By John D. Mitchell, JavaWorld.…

吴恩达老师深度学习视频课笔记:卷积神经网络

计算机视觉&#xff1a;包括图像分类(image classification)、目标检测(object detection)、风格迁移(neural style transfer)等等。边缘检测示例&#xff1a;神经网络的前几层可以检测边缘&#xff0c;然后后面几层可能检测到物体的部分&#xff0c;接下来靠后的一些层可能检测…

COCO 2019挑战赛,旷视研究院拿下三项计算机识别冠军 | ICCV 2019

出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;10月27日&#xff0c;两年一度的国际计算机视觉大会ICCV 2019&#xff08;InternationalConference on Computer Vision&#xff09;在韩国首尔开幕。作为ICCV 2019重头戏&#xff0c;COCO 是人工智能领域最具影响力的…

runners学习

runners是由salt-run命令调用的&#xff0c;一般我用的到就是jobs和manage模块。源代码是在./site-packages/salt/runners/下的。当然我们可以自定义runners。先谈谈jobs模块。包含active、lookup_jid、list_job、list_jobs、print_job五种方法。salt-run jobs.active ->返回…

Swift基础 - - 高德地图实践

高德地图开发需要自己到官网http://lbs.amap.com/console/ 注册一个ak&#xff0c;新建一个swift工程&#xff0c;然后在Info.plist中添加一个NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription。 高德地图的库以及依赖库加入到项目里面 需要的库如下…

Shell脚本示例代码

1. echo_printf_usage.sh: echo和printf的用法 #! /bin/bash# echo和printf的用法# echo是用于终端打印的基本命令.在默认情况下,echo在每次调用后会添加一个换行符 echo "hello, beijing" echo "$(pwd)" echo $(pwd) # 结果并不是希望得到的,将会输出: $…

「2019嵌入式智能国际大会」 399元超值学生票来啦,帮你豪省2600元!

2019 嵌入式智能国际大会即将来袭&#xff01;购票官网&#xff1a;https://dwz.cn/z1jHouwE物联网是继计算机、互联网和移动通信之后的又一次信息产业的革命性发展&#xff0c;在互联网和移动互联网高速发展的时代&#xff0c;几乎所有行业都有数据联网的需求。无论是国外的科…

ThinkPHP学习笔记之Model操作

2019独角兽企业重金招聘Python工程师标准>>> 1. 3种实例化model模型方法 a) new 命名空间GoodsModel(); b) D([“模型标志Goods”]) (之前版本会实例化自定义model对象&#xff0c;目前都实例化Model基类对象) i. 没有参数实例化一个Model对象、有参数也实例化一…

Ubuntu 14.04 64位上配置JDK操作步骤

1. 从 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载jdk-8u172-linux-x64.tar.gz; 2. 解压缩&#xff1a; tar -xvzf jdk-8u172-linux-x64.tar.gz 3. 创建/usr/jdk目录&#xff1a; sudo mkdir -p /usr/jdk 4. 将解压缩后的jd…

Swift语言实现代理传值

需求&#xff1a;利用代理实现反响传值&#xff08;以下例子采用点击第二个视图控制器中的按钮来改变第一个视图控制器中的Label的内容&#xff09; 一、创建RootViewController import Foundation import UIKitclass RootViewController:UIViewController,ChangeWordDelegate{…

亚马逊马超:如何使用DGL进行大规模图神经网络训练?

演讲嘉宾 | 马超&#xff08;亚马逊应用科学家&#xff09;整理 | 刘静 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;与传统基于张量&#xff08;Tensor&#xff09;的神经网络相比&#xff0c;图神经网络将图 (Graph) 作为输入&#xff0c;从图结构中学习潜在的知…

Python学习系列(六)(模块)

Python学习系列&#xff08;六&#xff09;(模块) Python学习系列&#xff08;五&#xff09;(文件操作及其字典) 一&#xff0c;模块的基本介绍 1&#xff0c;import引入其他标准模块 标准库&#xff1a;Python标准安装包里的模块。 引入模块的几种方式&#xff1a; i&#xf…

Ubuntu14.04 64位上配置终端显示git分支名称

之前在Ubuntu14.04上在终端上显示git分支名称基本上都使用oh-my-zsh&#xff0c;可以参考 https://blog.csdn.net/fengbingchun/article/details/77803322 &#xff0c;由于限制了权限&#xff0c;使得不能安装oh-my-zsh&#xff0c;显示错误如下&#xff1a;在 https://githu…

创建UITextField对象

//创建UITextField对象 UITextField * tf[[UITextField alloc]init];//设置UITextField的文字颜色tf.textColor[UIColor redColor];//设置UITextField的文本框背景颜色tf.backgroundColor[UIColor grayColor];//设置UITextField的边框的风格tf.borderStyleUITextBorderStyleRou…

non-local神经网络:通过非局部操作解决深度神经网络核心问题

译者 | 李杰出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;回想一下我们熟悉的CNN、RNN。如下图所示&#xff0c;这些神经网络模型都是基于局部区域进行操作&#xff0c;属于local operations。为了获得长距离依赖&#xff0c;也就是图像中非相邻像素点之间的关系&a…

fgets()用法笔记

为了避免缓冲区溢出&#xff0c;从终端读取输入时应当用fgets()代替gets()函数。但是这也将带来一个问题&#xff0c;因为fgets()的调用格式是&#xff1a; fgets (buf, MAX, fp)fgets (buf, MAX, stdin) buf是一个char数组的名称&#xff0c;MAX是字符串的最大长度&#xff0c…

iOS 上常用的两个功能:点击屏幕和return退出隐藏键盘和解决虚拟键盘

原文地址&#xff1a;http://blog.csdn.net/xiaotanyu13/article/details/7711954 iOS上面对键盘的处理很不人性化&#xff0c;所以这些功能都需要自己来实现&#xff0c; 首先是点击return和屏幕隐藏键盘 这个首先引用双子座的博客 http://my.oschina.net/plumsoft/blog/42545…

深度学习可解释性问题如何解决?图灵奖得主Bengio有一个解

作者 | Yoshua Bengio, Tristan Deleu等译者 | 刘畅&#xff0c;编辑 | Just出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;自 2012 年以来&#xff0c;深度学习的发展有目共睹&#xff0c;今年 3 月&#xff0c;为此做出巨大贡献的 Yoshua Bengio、Yann Lecun和Geo…

zepto打造一款移动端划屏插件

效果图 样式1 样式2 调用 正常情况下应该是后台生成的html代码&#xff0c;但还是写了一套操作tab页的方法 调用简便如下&#xff1a; <link rel"stylesheet" href"kslider.css" type"text/css"/> <script type"text/javascript&q…

swift使用xib绘制UIView

目标&#xff1a;用xib绘制一个UIView&#xff0c;在某个ViewController中调用。 三个文件&#xff1a;ViewController.swift DemoView.swift DemoView.xib 首先&#xff0c;可以专心将DemoView.xib画出来&#xff0c;别忘记DemoView.xib中UIView的一处设置 然后&#x…

吴恩达老师深度学习视频课笔记:深度卷积网络

Why look at case studies?&#xff1a;过去几年&#xff0c;计算机视觉研究中的大量研究都集中在如何把卷积层、池化层以及全连接层这些基本构件组合起来形成有效的卷积神经网络。找感觉最好的方法之一就是去看一些案例&#xff0c;就像很多人通过看别人的代码来学习编程一样…

测试工程师的好日子来啦?Testin发布AI测试产品,提升易用性和自动化效率

2019年10月26日&#xff0c;以"AI未来"为主题的第二届NCTS中国云测试行业峰会在北京国际会议中心正式开幕。在本次大会上&#xff0c;Testin 总裁徐琨正式发布测试业务Testin云测的全新AI产品iTestin。作为 Testin 人工智能战略中的重要一环&#xff0c;iTestin 融合…

Discuz DB层跨库映射关系表名前缀BUG修复后产生的新bug

新的逻辑引入了新的bug&#xff0c;会导致在跨多库连接时&#xff0c;产生表名前缀映射混乱&#xff0c;需要再做逻辑上的修复。 function table_name($tablename) {if(!empty($this->map) && !empty($this->map[$tablename])) {$id $this->map[$tablename];…