1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements.  See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership.  The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License.  You may obtain a copy of the License at
  9. *
  10. *     http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.apache.hadoop.mapreduce;
  19. import java.io.IOException;
  20. import java.security.PrivilegedExceptionAction;
  21. import org.apache.hadoop.conf.Configuration;
  22. import org.apache.hadoop.fs.Path;
  23. import org.apache.hadoop.io.RawComparator;
  24. import org.apache.hadoop.mapreduce.TaskAttemptID;
  25. import org.apache.hadoop.mapred.JobClient;
  26. import org.apache.hadoop.mapred.JobConf;
  27. import org.apache.hadoop.mapred.RunningJob;
  28. import org.apache.hadoop.mapred.TaskCompletionEvent;
  29. /**
  30. * The job submitter's view of the Job. It allows the user to configure the
  31. * job, submit it, control its execution, and query the state. The set methods
  32. * only work until the job is submitted, afterwards they will throw an
  33. * IllegalStateException.
  34. * job 提交者看到的job的视图。它允许用户配置job,提交job,控制job的执行,并且查询他的状态
  35. * set方法只有在job提交的时候才会工作
  36. */
  37. public class Job extends JobContext {
  38. public static enum JobState {DEFINE, RUNNING};//job的状态,有定义好的和正在运行
  39. private JobState state = JobState.DEFINE;
  40. private JobClient jobClient;
  41. private RunningJob info;
  42. /**
  43. * Creates a new {@link Job}
  44. * A Job will be created with a generic {@link Configuration}.
  45. *创建一个新的job,用通用的configuration
  46. * @return the {@link Job}
  47. * @throws IOException
  48. */
  49. public static Job getInstance() throws IOException {
  50. // create with a null Cluster
  51. return getInstance(new Configuration());
  52. }
  53. /**
  54. * Creates a new {@link Job} with a given {@link Configuration}.
  55. * The <code>Job</code> makes a copy of the <code>Configuration</code> so
  56. * that any necessary internal modifications do not reflect on the incoming
  57. * parameter.
  58. *使用给定的configuration创建job
  59. *这里对configuration进行了备份,如此,任何必要的对configuration内部修改,都不会影响传进来的conf参数
  60. * @param conf the {@link Configuration}
  61. * @return the {@link Job}
  62. * @throws IOException
  63. */
  64. public static Job getInstance(Configuration conf) throws IOException {
  65. // create with a null Cluster 没有任何集群的创建
  66. JobConf jobConf = new JobConf(conf);
  67. return new Job(jobConf);
  68. }
  69. /**
  70. * Creates a new {@link Job} with a given {@link Configuration}
  71. * and a given jobName.
  72. *用给定的conf和jobname
  73. * The <code>Job</code> makes a copy of the <code>Configuration</code> so
  74. * that any necessary internal modifications do not reflect on the incoming
  75. * parameter.
  76. *
  77. * @param conf the {@link Configuration}
  78. * @param jobName the job instance's name
  79. * @return the {@link Job}
  80. * @throws IOException
  81. */
  82. public static Job getInstance(Configuration conf, String jobName)
  83. throws IOException {
  84. // create with a null Cluster
  85. Job result = getInstance(conf);
  86. result.setJobName(jobName);
  87. return result;
  88. }
  89. public Job() throws IOException {
  90. this(new Configuration());
  91. }
  92. public Job(Configuration conf) throws IOException {
  93. super(conf, null);
  94. }
  95. public Job(Configuration conf, String jobName) throws IOException {
  96. this(conf);
  97. setJobName(jobName);
  98. }
  99. JobClient getJobClient() {
  100. return jobClient;
  101. }
  102. //确保job的状态
  103. private void ensureState(JobState state) throws IllegalStateException {
  104. if (state != this.state) {
  105. throw new IllegalStateException("Job in state "+ this.state +
  106. " instead of " + state);
  107. }
  108. if (state == JobState.RUNNING && jobClient == null) {
  109. throw new IllegalStateException("Job in state " + JobState.RUNNING +
  110. " however jobClient is not initialized!");
  111. }
  112. }
  113. /**
  114. * Set the number of reduce tasks for the job.
  115. * 设置reducer的个数 常用
  116. * @param tasks the number of reduce tasks
  117. * @throws IllegalStateException if the job is submitted
  118. */
  119. public void setNumReduceTasks(int tasks) throws IllegalStateException {
  120. ensureState(JobState.DEFINE);
  121. conf.setNumReduceTasks(tasks);
  122. }
  123. /**
  124. * Set the current working directory for the default file system.
  125. * 为默认文件系统 设置当前工作目录
  126. * @param dir the new current working directory.
  127. * @throws IllegalStateException if the job is submitted
  128. */
  129. public void setWorkingDirectory(Path dir) throws IOException {
  130. ensureState(JobState.DEFINE);
  131. conf.setWorkingDirectory(dir);
  132. }
  133. /**
  134. * Set the {@link InputFormat} for the job.
  135. * @param cls the <code>InputFormat</code> to use
  136. * @throws IllegalStateException if the job is submitted
  137. */
  138. public void setInputFormatClass(Class<? extends InputFormat> cls
  139. ) throws IllegalStateException {
  140. ensureState(JobState.DEFINE);
  141. conf.setClass(INPUT_FORMAT_CLASS_ATTR, cls, InputFormat.class);
  142. }
  143. /**
  144. * Set the {@link OutputFormat} for the job.
  145. * @param cls the <code>OutputFormat</code> to use
  146. * @throws IllegalStateException if the job is submitted
  147. */
  148. public void setOutputFormatClass(Class<? extends OutputFormat> cls
  149. ) throws IllegalStateException {
  150. ensureState(JobState.DEFINE);
  151. conf.setClass(OUTPUT_FORMAT_CLASS_ATTR, cls, OutputFormat.class);
  152. }
  153. /**
  154. * Set the {@link Mapper} for the job.
  155. * @param cls the <code>Mapper</code> to use
  156. * @throws IllegalStateException if the job is submitted
  157. */
  158. public void setMapperClass(Class<? extends Mapper> cls
  159. ) throws IllegalStateException {
  160. ensureState(JobState.DEFINE);
  161. conf.setClass(MAP_CLASS_ATTR, cls, Mapper.class);
  162. }
  163. /**
  164. * Set the Jar by finding where a given class came from.
  165. * 设置jar包,hadoop根据给定的class来寻找他的jar包
  166. * @param cls the example class
  167. */
  168. public void setJarByClass(Class<?> cls) {
  169. conf.setJarByClass(cls);
  170. }
  171. /**
  172. * Get the pathname of the job's jar.
  173. * @return the pathname
  174. */
  175. public String getJar() {
  176. return conf.getJar();
  177. }
  178. /**
  179. * Set the combiner class for the job.
  180. * @param cls the combiner to use
  181. * @throws IllegalStateException if the job is submitted
  182. */
  183. public void setCombinerClass(Class<? extends Reducer> cls
  184. ) throws IllegalStateException {
  185. ensureState(JobState.DEFINE);
  186. conf.setClass(COMBINE_CLASS_ATTR, cls, Reducer.class);
  187. }
  188. /**
  189. * Set the {@link Reducer} for the job.
  190. * @param cls the <code>Reducer</code> to use
  191. * @throws IllegalStateException if the job is submitted
  192. */
  193. public void setReducerClass(Class<? extends Reducer> cls
  194. ) throws IllegalStateException {
  195. ensureState(JobState.DEFINE);
  196. conf.setClass(REDUCE_CLASS_ATTR, cls, Reducer.class);
  197. }
  198. /**
  199. * Set the {@link Partitioner} for the job.
  200. * @param cls the <code>Partitioner</code> to use
  201. * @throws IllegalStateException if the job is submitted
  202. */
  203. public void setPartitionerClass(Class<? extends Partitioner> cls
  204. ) throws IllegalStateException {
  205. ensureState(JobState.DEFINE);
  206. conf.setClass(PARTITIONER_CLASS_ATTR, cls, Partitioner.class);
  207. }
  208. /**
  209. * Set the key class for the map output data. This allows the user to
  210. * specify the map output key class to be different than the final output
  211. * value class.
  212. *
  213. * @param theClass the map output key class.
  214. * @throws IllegalStateException if the job is submitted
  215. */
  216. public void setMapOutputKeyClass(Class<?> theClass
  217. ) throws IllegalStateException {
  218. ensureState(JobState.DEFINE);
  219. conf.setMapOutputKeyClass(theClass);
  220. }
  221. /**
  222. * Set the value class for the map output data. This allows the user to
  223. * specify the map output value class to be different than the final output
  224. * value class.
  225. *
  226. * @param theClass the map output value class.
  227. * @throws IllegalStateException if the job is submitted
  228. */
  229. public void setMapOutputValueClass(Class<?> theClass
  230. ) throws IllegalStateException {
  231. ensureState(JobState.DEFINE);
  232. conf.setMapOutputValueClass(theClass);
  233. }
  234. /**
  235. * Set the key class for the job output data.
  236. *
  237. * @param theClass the key class for the job output data.
  238. * @throws IllegalStateException if the job is submitted
  239. */
  240. public void setOutputKeyClass(Class<?> theClass
  241. ) throws IllegalStateException {
  242. ensureState(JobState.DEFINE);
  243. conf.setOutputKeyClass(theClass);
  244. }
  245. /**
  246. * Set the value class for job outputs.
  247. *
  248. * @param theClass the value class for job outputs.
  249. * @throws IllegalStateException if the job is submitted
  250. */
  251. public void setOutputValueClass(Class<?> theClass
  252. ) throws IllegalStateException {
  253. ensureState(JobState.DEFINE);
  254. conf.setOutputValueClass(theClass);
  255. }
  256. /**
  257. * Define the comparator that controls how the keys are sorted before they
  258. * are passed to the {@link Reducer}.
  259. * @param cls the raw comparator
  260. * @throws IllegalStateException if the job is submitted
  261. */
  262. public void setSortComparatorClass(Class<? extends RawComparator> cls
  263. ) throws IllegalStateException {
  264. ensureState(JobState.DEFINE);
  265. conf.setOutputKeyComparatorClass(cls);
  266. }
  267. /**
  268. * Define the comparator that controls which keys are grouped together
  269. * for a single call to
  270. * {@link Reducer#reduce(Object, Iterable,
  271. *                       org.apache.hadoop.mapreduce.Reducer.Context)}
  272. * @param cls the raw comparator to use
  273. * @throws IllegalStateException if the job is submitted
  274. */
  275. public void setGroupingComparatorClass(Class<? extends RawComparator> cls
  276. ) throws IllegalStateException {
  277. ensureState(JobState.DEFINE);
  278. conf.setOutputValueGroupingComparator(cls);
  279. }
  280. /**
  281. * Set the user-specified job name.
  282. *
  283. * @param name the job's new name.
  284. * @throws IllegalStateException if the job is submitted
  285. */
  286. public void setJobName(String name) throws IllegalStateException {
  287. ensureState(JobState.DEFINE);
  288. conf.setJobName(name);
  289. }
  290. /**
  291. * Turn speculative execution on or off for this job.
  292. * 设置推测执行的开关
  293. * @param speculativeExecution <code>true</code> if speculative execution
  294. *                             should be turned on, else <code>false</code>.
  295. */
  296. public void setSpeculativeExecution(boolean speculativeExecution) {
  297. ensureState(JobState.DEFINE);
  298. conf.setSpeculativeExecution(speculativeExecution);
  299. }
  300. /**
  301. * Turn speculative execution on or off for this job for map tasks.
  302. *
  303. * @param speculativeExecution <code>true</code> if speculative execution
  304. *                             should be turned on for map tasks,
  305. *                             else <code>false</code>.
  306. */
  307. public void setMapSpeculativeExecution(boolean speculativeExecution) {
  308. ensureState(JobState.DEFINE);
  309. conf.setMapSpeculativeExecution(speculativeExecution);
  310. }
  311. /**
  312. * Turn speculative execution on or off for this job for reduce tasks.
  313. *
  314. * @param speculativeExecution <code>true</code> if speculative execution
  315. *                             should be turned on for reduce tasks,
  316. *                             else <code>false</code>.
  317. */
  318. public void setReduceSpeculativeExecution(boolean speculativeExecution) {
  319. ensureState(JobState.DEFINE);
  320. conf.setReduceSpeculativeExecution(speculativeExecution);
  321. }
  322. /**
  323. * Get the URL where some job progress information will be displayed.
  324. * 得到 一些job 进度信息会展示的url地址
  325. * @return the URL where some job progress information will be displayed.
  326. */
  327. public String getTrackingURL() {
  328. ensureState(JobState.RUNNING);
  329. return info.getTrackingURL();
  330. }
  331. /**
  332. * Get the <i>progress</i> of the job's setup, as a float between 0.0
  333. * and 1.0.  When the job setup is completed, the function returns 1.0.
  334. *
  335. * @return the progress of the job's setup.
  336. * @throws IOException
  337. */
  338. public float setupProgress() throws IOException {
  339. ensureState(JobState.RUNNING);
  340. return info.setupProgress();
  341. }
  342. /**
  343. * Get the <i>progress</i> of the job's map-tasks, as a float between 0.0
  344. * and 1.0.  When all map tasks have completed, the function returns 1.0.
  345. *
  346. * @return the progress of the job's map-tasks.
  347. * @throws IOException
  348. */
  349. public float mapProgress() throws IOException {
  350. ensureState(JobState.RUNNING);
  351. return info.mapProgress();
  352. }
  353. /**
  354. * Get the <i>progress</i> of the job's reduce-tasks, as a float between 0.0
  355. * and 1.0.  When all reduce tasks have completed, the function returns 1.0.
  356. *
  357. * @return the progress of the job's reduce-tasks.
  358. * @throws IOException
  359. */
  360. public float reduceProgress() throws IOException {
  361. ensureState(JobState.RUNNING);
  362. return info.reduceProgress();
  363. }
  364. /**
  365. * Check if the job is finished or not.
  366. * This is a non-blocking call.
  367. *
  368. * @return <code>true</code> if the job is complete, else <code>false</code>.
  369. * @throws IOException
  370. */
  371. public boolean isComplete() throws IOException {
  372. ensureState(JobState.RUNNING);
  373. return info.isComplete();
  374. }
  375. /**
  376. * Check if the job completed successfully.
  377. *
  378. * @return <code>true</code> if the job succeeded, else <code>false</code>.
  379. * @throws IOException
  380. */
  381. public boolean isSuccessful() throws IOException {
  382. ensureState(JobState.RUNNING);
  383. return info.isSuccessful();
  384. }
  385. /**
  386. * Kill the running job.  Blocks until all job tasks have been
  387. * killed as well.  If the job is no longer running, it simply returns.
  388. * 杀掉正在运行的job 直到所有的job tasks都被杀掉之后 才会停止。
  389. * 如果job不再运行来 他就会返回
  390. * @throws IOException
  391. */
  392. public void killJob() throws IOException {
  393. ensureState(JobState.RUNNING);
  394. info.killJob();
  395. }
  396. /**
  397. * Get events indicating completion (success/failure) of component tasks.
  398. *
  399. * @param startFrom index to start fetching events from
  400. * @return an array of {@link TaskCompletionEvent}s
  401. * @throws IOException
  402. */
  403. public TaskCompletionEvent[] getTaskCompletionEvents(int startFrom
  404. ) throws IOException {
  405. ensureState(JobState.RUNNING);
  406. return info.getTaskCompletionEvents(startFrom);
  407. }
  408. /**
  409. * Kill indicated task attempt.
  410. *
  411. * @param taskId the id of the task to be terminated.
  412. * @throws IOException
  413. */
  414. public void killTask(TaskAttemptID taskId) throws IOException {
  415. ensureState(JobState.RUNNING);
  416. info.killTask(org.apache.hadoop.mapred.TaskAttemptID.downgrade(taskId),
  417. false);
  418. }
  419. /**
  420. * Fail indicated task attempt.
  421. *
  422. * @param taskId the id of the task to be terminated.
  423. * @throws IOException
  424. */
  425. public void failTask(TaskAttemptID taskId) throws IOException {
  426. ensureState(JobState.RUNNING);
  427. info.killTask(org.apache.hadoop.mapred.TaskAttemptID.downgrade(taskId),
  428. true);
  429. }
  430. /**
  431. * Gets the counters for this job.
  432. *
  433. * @return the counters for this job.
  434. * @throws IOException
  435. */
  436. public Counters getCounters() throws IOException {
  437. ensureState(JobState.RUNNING);
  438. return new Counters(info.getCounters());
  439. }
  440. private void ensureNotSet(String attr, String msg) throws IOException {
  441. if (conf.get(attr) != null) {
  442. throw new IOException(attr + " is incompatible with " + msg + " mode.");
  443. }
  444. }
  445. /**
  446. * Sets the flag that will allow the JobTracker to cancel the HDFS delegation
  447. * tokens upon job completion. Defaults to true.
  448. */
  449. public void setCancelDelegationTokenUponJobCompletion(boolean value) {
  450. ensureState(JobState.DEFINE);
  451. conf.setBoolean(JOB_CANCEL_DELEGATION_TOKEN, value);
  452. }
  453. /**
  454. * Default to the new APIs unless they are explicitly set or the old mapper or
  455. * reduce attributes are used.
  456. * @throws IOException if the configuration is inconsistant
  457. */
  458. private void setUseNewAPI() throws IOException {
  459. int numReduces = conf.getNumReduceTasks();
  460. String oldMapperClass = "mapred.mapper.class";
  461. String oldReduceClass = "mapred.reducer.class";
  462. conf.setBooleanIfUnset("mapred.mapper.new-api",
  463. conf.get(oldMapperClass) == null);
  464. if (conf.getUseNewMapper()) {
  465. String mode = "new map API";
  466. ensureNotSet("mapred.input.format.class", mode);
  467. ensureNotSet(oldMapperClass, mode);
  468. if (numReduces != 0) {
  469. ensureNotSet("mapred.partitioner.class", mode);
  470. } else {
  471. ensureNotSet("mapred.output.format.class", mode);
  472. }
  473. } else {
  474. String mode = "map compatability";
  475. ensureNotSet(JobContext.INPUT_FORMAT_CLASS_ATTR, mode);
  476. ensureNotSet(JobContext.MAP_CLASS_ATTR, mode);
  477. if (numReduces != 0) {
  478. ensureNotSet(JobContext.PARTITIONER_CLASS_ATTR, mode);
  479. } else {
  480. ensureNotSet(JobContext.OUTPUT_FORMAT_CLASS_ATTR, mode);
  481. }
  482. }
  483. if (numReduces != 0) {
  484. conf.setBooleanIfUnset("mapred.reducer.new-api",
  485. conf.get(oldReduceClass) == null);
  486. if (conf.getUseNewReducer()) {
  487. String mode = "new reduce API";
  488. ensureNotSet("mapred.output.format.class", mode);
  489. ensureNotSet(oldReduceClass, mode);
  490. } else {
  491. String mode = "reduce compatability";
  492. ensureNotSet(JobContext.OUTPUT_FORMAT_CLASS_ATTR, mode);
  493. ensureNotSet(JobContext.REDUCE_CLASS_ATTR, mode);
  494. }
  495. }
  496. }
  497. /**
  498. * Submit the job to the cluster and return immediately.
  499. * 提交job到集群上面 并且立刻返回
  500. * @throws IOException
  501. */
  502. public void submit() throws IOException, InterruptedException,
  503. ClassNotFoundException {
  504. ensureState(JobState.DEFINE);
  505. setUseNewAPI();
  506. // Connect to the JobTracker and submit the job
  507. //连接到jobtracker 并且提交作业
  508. connect();
  509. info = jobClient.submitJobInternal(conf);//这里才真正的提交作业
  510. super.setJobID(info.getID());
  511. state = JobState.RUNNING;
  512. }
  513. /**
  514. * Open a connection to the JobTracker
  515. * 打开到jobtracker的连接
  516. * @throws IOException
  517. * @throws InterruptedException
  518. */
  519. private void connect() throws IOException, InterruptedException {
  520. ugi.doAs(new PrivilegedExceptionAction<Object>() {
  521. public Object run() throws IOException {
  522. jobClient = new JobClient((JobConf) getConfiguration());
  523. return null;
  524. }
  525. });
  526. }
  527. /**
  528. * Submit the job to the cluster and wait for it to finish.
  529. * @param verbose print the progress to the user
  530. * @return true if the job succeeded
  531. * @throws IOException thrown if the communication with the
  532. *         <code>JobTracker</code> is lost
  533. */
  534. public boolean waitForCompletion(boolean verbose
  535. ) throws IOException, InterruptedException,
  536. ClassNotFoundException {
  537. if (state == JobState.DEFINE) {
  538. submit();
  539. }
  540. if (verbose) {
  541. jobClient.monitorAndPrintJob(conf, info);
  542. } else {
  543. info.waitForCompletion();
  544. }
  545. return isSuccessful();
  546. }
  547. }

job源码分析的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

  10. ABP源码分析四:Configuration

    核心模块的配置 Configuration是ABP中设计比较巧妙的地方.其通过AbpStartupConfiguration,Castle的依赖注入,Dictionary对象和扩展方法很巧妙的实现了配 ...

随机推荐

  1. Python中的slice操作

    Python中slice操作的完整语法: # i默认是0 # j默认是len(S) # k的步长,默认为+1 S[i:j:k] 其中i,j,k都可以是负数: 若i < 0或者k<0,等价于 ...

  2. 视频播放截图及简要文字介绍——Thunder团队

    视频播放截图及简要文字介绍 图一:团队Logo ——从此我们有了自己的标志 图二:扫描本地书籍 ——可阅读本地的喜爱书籍 图三:在本地添加自己喜爱的图书 ——将自己喜爱的书籍加入书架,方便阅读 图四: ...

  3. Java实验二实验报告:java面向对象程序设计

    java实验二实验报告 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计模式 实验 ...

  4. c#非界面线程控制控件

    private delegate void FlushCilent(); Invoke(new FlushCilent(databaseConnect));

  5. 解决python中文编码错误问题

    对于初学者而言,编码问题或许还没有没重视起来,但是编码问题是中文开发者必须面对的.今天来看下python开发中如何解决编码问题.注意:本篇讲的是最常见的一种编码问题,其他编码问题,如json函数引起的 ...

  6. Alpha冲刺——第四天

    Alpha第四天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  7. Bootstrap 导航条理解

    以下理论内容copy自Bootstrap中文网 (一个不错的bootstrap学习网站) 导航条 默认样式的导航条 导航条是在您的应用或网站中作为导航页头的响应式基础组件.它们在移动设备上可以折叠(并 ...

  8. CCS3 动画-鼠标放上去放大背景图片

    ---〉 效果如上,一个简单的过渡放大效果, <!DOCTYPE HTML> <html> <body> <style> #test{ width:30 ...

  9. BZOJ 1191 超级英雄(二分图匹配)

    把题目作为s集,锦囊作为t集.把每个题目和它可以用的锦囊连边,这样就构成了一个二分图,求出这个二分图最大匹配. 但是这个最大匹配有限制条件,就是对于每个可能的匹配集,如果s集的i点有匹配,那么i-1点 ...

  10. I/O复用----poll

    2018-08-01 (星期三)poll(): #include <sys/poll.h> int poll (struct pollfd *fd, unsigned int nfds, ...