Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具... ...当前其支持的语言限于Java、Groovy、Kotlin和Scala...

嗯,没错,这就是我把它归类到 编程语言/Java 而不是 软件/编译 的原因。

相比于maven,Eclipse对于gradle的可视化操作的友好程度大大下降。只提供最基础的项目创建、任务运行(修改了配置文件之后居然还不会自动更新任务)和配置文件高亮功能。甚至连依赖配置都只能自己动手修改文件完成。虽然不难,但是不直观啊,对新手入门也不友好。反正我是搜了好久教程,七拼八凑弄出来的。

简要列出三大运行项目的方法[1]

  1. 暴力寻找主类运行。由于gradle只是一个项目构建工具(和cmake有点像?),并不负责对被处理对象进行运行操作,故默认状态下我们只能得到编译好的class文件。故最原始粗暴的方法便是手动为Eclipse指定一个运行时的主类。而当Eclipse在检测到所有项目文件均已编译好时,会直接运行项目,间接达到了目的:因为依赖配置使用的是gradle,直接使用Eclipse调用javac编译的话可能会出现缺少包的错误。

  2. 加载application插件。gradle可以通过插件扩展其功能。application插件能够为gradle添加一个Application Tasks/run的任务,通过该任务可以直接运行项目。 在build.gradle文件的最外层里添加

    apply plugin 'application'
    mainClassName = 'your.main.class'

    your.main.class换成项目的入口类,会自动调用其main方法运行项目。 没有mainClassName的话,buildrun任务都会出错,因为application插件将不知道你需要将哪个包作为应用程序运行。

  3. 这个更暴力了。。编译成jar然后自己去命令行运行(捂脸)
    jar {
    manifest.attributes 'Main-Class': 'com.mycompany.Main'
    from configuration.compile.collect { zipTree it}
    }

    然后gradle/gradlew build生成jar包,然后用对应的java命令执行(通常是java -jar file.jar)即可。

添加依赖的方法:

  1. 最简单粗暴(对应maven):

    <scope> '<group>:<artifact>:<version>'
    =======================================================
    <scope> IN compile, test, testCompile, runtime, etc.

    scope与maven中的部分对应。 例:runtime 'mysql:mysql-connector-java' << 最后一个版本号可以省略,应该是默认取最新版本吧?

  2. 优雅一点:

    <scope> group: '...', name: '...', version: '...'
    =======================================================
    <scope> IN compile, test, testCompile, runtime, etc.

    例:runtime group: 'mysql', name: 'mysql-connector-java', version: '8.0.16'

  3. 本地文件:
    <scope> fileTree(dir: 'lib', includes: ['mysql-connector-java-8.0.16.jar'])
    =======================================================
    <scope> IN compile, test, testCompile, runtime, etc.

    该写法会让gradle到项目根目录下的lib文件夹里寻找mysql-connector-java-8.0.16.jar

参考: [1] https://www.cnblogs.com/yongheng20/p/6161160.html

在做计算机组成题目的时候,遇到的神奇的这么一题:

假设某计算机按字编址,Cache 有 4 个行,Cache 和主存之间交换的块为 1 个字。若 Cache 的内容初始为空,采用 2 路组相联映射方式和 LRU 替换算法。当访问的主存地址依次为 0,4,8,2,0,6,8,6,4,8 时,命中 Cache 的次数是?

当时就有点纳闷:访问的主存地址都是偶数,若是最基本的组相联的映射关系的话,岂不是只有一半的缓存是有效的? 按照这种方法计算,最终是只有一次缓存命中的。

但是看着总感觉隐隐不对劲,再理论化的题目,也不应该出反实际情况的例子啊,哪有这种暴殄天物的操作。 再去翻翻书,书上也只对于Intel Pentium处理器内的2路组相联缓存做了一个让人捉摸不透的简要解释:

因为在两路组相联cache中,一个主存块只能调入cache的一个特定组的两块中的一块,因此只需设置一个标志位,当两块中的一块(假设为A块)被命中时,标志位置1,而另一块(假设为B块)被命中时,标志位清0。当需要替换是,只需检查此标志位的状态即可:为0替换A块,为1替换B块。Pentium CPU内的数据cache采用的是一个两路组相联结构,使用的就是这种简化的LRU替换算法。

(若是至此,或许可能存在的读者已经领悟其中的意思的话,可直接跳至文尾)

后来在网上找也没看到说有什么官方权威的解释,不过在某度文库的一个ppt里找到了这样的题解: https://wenku.baidu.com/view/e1c69c0cf78a6529647d5340.html 为了防止原链接抽抽,贴张截图吧

也就是说,根据这个题解在对存储单元在缓存中的映射中,采取了连续两个分为一组的规则的操作,可以大胆猜测:所谓的2路组相联操作,就是在缓存分组的时候每两个缓存单元一组,且在做映射的时候将连续的两个主存单元映射至同一组缓存分组。通过这个猜测,我们可以解释在该题解中,为什么4个缓存单元要画成2x2的形式,以及为什么分组是两个连续主存单元分至同一缓存块。

此时回过头去看上面的书本引用,会发现似乎清楚了许多:一组中只有两个缓存块,当有新数据进入时,替换的只能不是A块就是B块,因而只要根据LRU算法,哪个最近被使用的“得分”低,就会被替换出去,因而只需要一位二进制就可以表示LRU算法中的标志位。再说通俗一点,对于这个缓存块,我更愿意把它叫做“块中块”,因为首先主存在分组映射的时候,就已经需要按照一定的数学规律进行归类,而这个“2路”决定了其中归类时的连续存储单元数为2,而不是默认时的1。

据此,作出如下抽象公式式的结论: 假设有N个缓存单元可以分解为两个正整数m, n的乘积,定义n路组相联的映射规则如下: 将主存单元和N个缓存单元均按照每n个一组划分(即有m个缓存单元组),将所有(km+i)个主存单元组映射至第i个缓存单元组。 其中i为[0, m)区间内的整数,k为使得第(km+i)个主存单元组存在的自然数值。

但是,到目前为止,尚未见过2路以上的组相联缓存映射。 假设要实现的话,标记为可做如下设计: 1) 一组内有多少个寄存器就用多少位二进制,用0和1区分不需要和需要替换的寄存器,可作为选通信号直接输给硬件电路; 2) 使用二进制地址来表示需要替换的寄存单元编号,用译码器传递选通信号。

没错,回去点个题,这篇文章大部分基于个人分析,目前尚未找到权威书籍或资料证明其正确性。可能是因为太懒还没找到

============================================== 后续更新

回去翻书后,发现书上没有对n路组相联进行详细的叙述。实际上,这个n路为了方便寻址和提高硬件利用率,通常会设置为2的自然数幂(1, 2, 4, 8, ...)。在做题时,需要利用的就是组相联中的路数的含义,包括 缓存的划分主存的映射规则 。根据这个规则,以及部分博客所提供的定义,能够正确地完成题目这才是重点

  1. 先到github上拉一份发布版本的源码包下来
  2. 安装python, bazel(Google的开源编译工具), 以及gcc等编译环境必备工具 其中bazel的新版本在编译时会报错,根据stackoverflow上的建议,使用1.17.2版本的,可在其github的发布页面找到下载。
  3. python安装numpy包。
  4. ./configure
  5. bazel build --config=mkl --config=opt //tensorflow/tools/pip_package:build_pip_package 生成轮子,用于pip安装。由于打算使用intel的mkl进行加速,添加了--config=mkl的选项。不需要的可以删除。

该错误通常在update语句报出。原因是企图在set子句中调用from子句中给表设立的别名。这个别名通常用于子句中的where子句的条件判定。 例:

UPDATE Tab
SET THIS.prop1 = (SELECT propx FROM Tab WHERE propy = THIS.propy)
FROM Tab THIS
WHERE propz = valz;

预期效果是希望将满足where条件的数据进新更新,实际上会报出如下错误: The multi-part identifier 'THIS.prop1' could not be bound. 原因是DBMS并搞不懂你的THIS和上面提到的Tab之间的关系。 解决方法:UPDATE Tab->UPDATE THIS,即把要更新的表名设置为为自己定义的别名即可。

参考: https://blog.csdn.net/dxnn520/article/details/7915198

实验课上,要求将一个角色的权限授予另一个角色。 在咕果上搜了老半天,结果只找到怎么把角色赋予用户。(汗,怎么这波技术含量这么低) 然后找到了ALTER ROLE ADD MEMBEREXEC sp_roleaddmember两个指令用于添加用户至角色。 用法:

ALTER ROLE <role-name> ADD MEMBER <user-name>
EXEC sp_roleaddmember [@rolename=]<role-name>, [@membername=]<user-name>

根据StackOverflow上该回答中一位用户所言,两者在SQL Server 2012中没有区别,参考资料如下: https://msdn.microsoft.com/en-us/library/ms189775.aspx https://msdn.microsoft.com/en-us/library/ms187750.aspx

但是在使用时,惊奇的发现在可以将Role作为参数填入以上操作的user-name部分,可以正常执行不会报错。 在子角色(user-name)的所有权限中查不到父角色(role-name)的权限,但是在父角色的成员表中可以看到子角色。 经过尝试后,发现直接对用户赋予子角色时,会自动给用户注册一个父角色的权限。 也就是说,直接把需要附加给角色的角色权限作为该角色的父角色,数据库便会在执行指令时自动赋予其父角色的权限。

例: 有两个角色,JuniorRoleSeniorRole,要将JuniorRole的权限赋予SeniorRole(显然高级用户通常应该拥有初级用户的全部权限),在SQL Server中可以这么做:

ALTER ROLE JuniorRole ADD MEMBER SeniorRole;

之后在进行用户授权时,ALTER ROLE SeniorRole add SeniorUser不仅会为SeniorUser赋予SeniorRole的角色,还会为其赋予JuniorRole的角色,目的达成。