Hadoop RPC框架

原文:http://blog.csdn.net/thomas0yang/article/details/41211259

----------------------------------------------------------------------------------------------

1、RPC框架概述
1.1 RPC(Remote Procedure Call Protocol)——遠程過程調用協議,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通信程序之間攜帶信息數據。在OSI網絡通信模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分布式多程序在內的應用程序更加容易。
1.2 RPC通常采用客戶端服務器模型,其框架主要有以下幾部分
  • 通信模塊:實現請求應該協議。主要分為同步方式和異步方式。
  • stub程序:客戶端和服務器均包含stub程序,可以看做代理程序。使得遠程函數表現的跟本地調用一樣,對用戶程序完全透明。
  • 調度程序:接受來自通信模塊的請求消息,根據標識選擇stub程序處理。并發量大一般采用線程池處理。
  • 客戶程序/服務過程:請求發出者和請求的處理者。
1.3 RPC流程圖


2、Hadoop RPC基本框架
2.1Hadoop RPC的使用方法見代碼
服務
public interface MyBiz extends VersionedProtocol {
??? long PROTOCOL_VERSION = 12321443L;
??? String hello(String name);
}
public class MyBizImpl implements MyBiz {
??? @Override
??? public long getProtocolVersion(String arg0, long arg1) throws IOException {
??????? return PROTOCOL_VERSION;
??? }

??? @Override
??? public String hello(String name) {
??????? System. out.println( "invoked");
??????? return "hello " + name;
??? }
}

服務器
public class MyServer {
??? public static final String SERVER_ADDRESS = "localhost";
??? public static final int SERVER_PORT = 12345;

??? public static void main(String[] args) throws IOException {
??????? Server server = RPC. getServer(new MyBizImpl(), SERVER_ADDRESS, SERVER_PORT , new Configuration());
??????? server.start();
??? }
}

客戶端
public class MyClient {
??? public static void main(String[] args) throws IOException {
??????? MyBiz proxy = (MyBiz) RPC. getProxy(MyBiz.class, MyBiz.PROTOCOL_VERSION,
??????????????? new InetSocketAddress(MyServer. SERVER_ADDRESS,MyServer.SERVER_PORT),
??????????????? new Configuration());
??????? String result = proxy.hello( "5");
??????? System. out.println(result);
??????? RPC.stopProxy(proxy);
??? }
}

2.2 org.apache.hadoop.ipc.RPC類解析
RPC類主要包含三部分:
  • ClientCache(成員變量):根據用戶提供的SocketFactory來緩存Client對象,以便重用Client對象。
  • Server(內部類):繼承Server抽象類,利用反射實現了call方法,即客戶端請求的方法和對應參數完成方法調用。
  • Invocation(內部類):將要調用的方法名和參數打包成可序列化的對象,方便客戶端和服務器之間傳遞。

2.3 客戶端和服務器端的關系
  • Client-NameNode之間,其中NameNode是服務器
  • Client-DataNode之間,其中DataNode是服務器
  • DataNode-NameNode之間,其中NameNode是服務器
  • DataNode-DateNode之間,其中某一個DateNode是服務器,另一個是客戶端
2.4?org.apache.hadoop.ipc.Client類解析
2.4.1 Client類中主要包含:
  • Call(內部類):封裝了一個RPC請求,包含5個成員變量,唯一表示id、函數調用信息param、函數返回值value、函數異常信息error、函數完成標識done。Hadoop rpc?server采用異步方式處理客戶端請求,使得遠程過程調用的發生順序和返回順序無直接關系,而客戶端正是通過id識別不同的函數調用。當客戶端向服務器發送請求,只需填充id和param兩個變量,其余3個變量由服務器端根據函數執行情況填充。
  • Connection(內部類,一個線程):是client和server之間的一個通信連接,封裝了連接先關的基本信息和操作。基本信息包括:通信連接唯一標識remoteId(ConnectionId)、與Server端通信的scoket、網絡輸入輸出流in/out、保存RPC請求的哈希表calls(Hashtable<Integer, Call>)。操作包括:addCall將一個Call對象添加到哈希表中;sendParam想服務器端發送RPC請求;receiveResponse從服務器端接收已經處理完成的RPC請求;run調用receiveResponse方法,等待返回結果。
  • ConnectionId(內部類):連接的標記(包括server地址,協議,其他一些連接的配置項信息)
  • ParallelCall(內部類):實現并行調用的請求
  • ParallelResults(內部類):并行調用的執行結果
2.4.2 Client類中主要對外通過兩個接口,分別用于單個遠程調用和批量遠程調用。
public Writable call(Writable param, ConnectionId remoteId)? throws InterruptedException, IOException
public Writable call(Writable param, InetSocketAddress addr,? Class<?> protocol, UserGroupInformation ticket,
int rpcTimeout, Configuration conf)? throws InterruptedException, IOException

2.4.3 調用流程分析,當調用call函數執行某個遠程方法時,有以下幾個步驟:
1)創建一個Connection對象,并將遠程方法調用信息封裝成Call對象,放到Connection對象中的哈希表中;
2)調用Connection類中的sendRpcRequest()方法將當前Call對象發送給Server端;
3)Server端處理完RPC請求后,將結果通過網絡返回給Client端,Client端通過receiveRpcResponse()函數獲取結果;
4)Client檢查結果處理狀態(成功還是失敗),并將對應Call對象從哈希表中刪除。

2.4.4 一個Client包含多個連接,private Hashtable<ConnectionId, Connection> connections = new Hashtable<ConnectionId, Connection>();

2.5?org.apache.hadoop.ipc.Server類解析

2.5.1 背景
Hadoop采用了Master/Slave結構,其中Master是整個系統的單點,如NameNode或JobTracker,這是制約系統性能和可擴展性的最關鍵因素之一;而Master通過ipc.Server接收并處理所有Slave發送的請求,這就要求ipc.Server 將高并發和可擴展性作為設計目標。為此,ipc.Server采用了很多提高并發處理能力的技術,主要包括線程池、事件驅動和Reactor設計模式等,這些技術均采用了JDK自帶的庫實現,這里重點分析它是如何利用Reactor設計模式提高整體性能的。

2.5.2 reactor設計模式
Reactor是并發編程中的一種基于事件驅動的設計模式,它具有以下兩個特點:通過派發/分離I/O操作事件提高系統的并發性能;提供了粗粒度的并發控制,使用單線程實現,避免了復雜的同步處理。典型的Reactor實現原理如圖所示。

典型的Reactor模式中主要包括以下幾個角色。
  • Reactor:I/O事件的派發者。
  • Acceptor:接受來自Client的連接,建立與Client對應的Handler,并向Reactor注冊此Handler。
  • Handler:與一個Client通信的實體,并按一定的過程實現業務的處理。Handler內部往往會有更進一步的層次劃分,用來抽象諸如read、decode、compute、encode和send等過程。在Reactor模式中,業務邏輯被分散的I/O事件所打破,所以Handler需要有適當的機制在所需的信息還不全(讀到一半)的時候保存上下文,并在下一次I/O事件到來的時候(另一半可讀)能繼續上次中斷的處理。
  • Reader/Sender:為了加速處理速度,Reactor模式往往構建一個存放數據處理線程的線程池,這樣數據讀出后,立即扔到線程池中等待后續處理即可。為此,Reactor模式一般分離Handler中的讀和寫兩個過程,分別注冊成單獨的讀事件和寫事件,并由對應的Reader和Sender線程處理。
2.5.3 java nio代碼實例
package com.sohu.tv.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
* NIO服務端
* @author 小路
*/
public class NIOServer {
??? //通道管理器
??? private Selector selector;

??? /**
???? * 獲得一個ServerSocket通道,并對該通道做一些初始化的工作
???? * @param port? 綁定的端口號
???? * @throws IOException
???? */
??? public void initServer(int port) throws IOException {
??????? // 獲得一個ServerSocket通道
??????? ServerSocketChannel serverChannel = ServerSocketChannel.open();
??????? // 設置通道為非阻塞
??????? serverChannel.configureBlocking(false);
??????? // 將該通道對應的ServerSocket綁定到port端口
??????? serverChannel.socket().bind(new InetSocketAddress(port));
??????? // 獲得一個通道管理器
??????? this.selector = Selector.open();
??????? //將通道管理器和該通道綁定,并為該通道注冊SelectionKey.OP_ACCEPT事件,注冊該事件后,
??????? //當該事件到達時,selector.select()會返回,如果該事件沒到達selector.select()會一直阻塞。
??????? serverChannel.register(selector, SelectionKey.OP_ACCEPT);
??? }

??? /**
???? * 采用輪詢的方式監聽selector上是否有需要處理的事件,如果有,則進行處理
???? * @throws IOException
???? */
??? @SuppressWarnings("unchecked")
??? public void listen() throws IOException {
??????? System.out.println("服務端啟動成功!");
??????? // 輪詢訪問selector
??????? while (true) {
??????????? //當注冊的事件到達時,方法返回;否則,該方法會一直阻塞
????????????selector.select();
??????????? // 獲得selector中選中的項的迭代器,選中的項為注冊的事件
??????????? Iterator ite = this.selector.selectedKeys().iterator();
??????????? while (ite.hasNext()) {
??????????????? SelectionKey key = (SelectionKey) ite.next();
??????????????? // 刪除已選的key,以防重復處理
??????????????? ite.remove();
??????????????? // 客戶端請求連接事件
??????????????? if (key.isAcceptable()) {
??????????????????? ServerSocketChannel server = (ServerSocketChannel) key
??????????????????????????? .channel();
??????????????????? // 獲得和客戶端連接的通道
??????????????????? SocketChannel channel = server.accept();
??????????????????? // 設置成非阻塞
??????????????????? channel.configureBlocking(false);

??????????????????? //在這里可以給客戶端發送信息哦
??????????????????? channel.write(ByteBuffer.wrap(new String("向客戶端發送了一條信息").getBytes()));
??????????????????? //在和客戶端連接成功之后,為了可以接收到客戶端的信息,需要給通道設置讀的權限。
????????????????????channel.register(this.selector, SelectionKey.OP_READ);

??????????????????? // 獲得了可讀的事件
??????????????? } else if (key.isReadable()) {
??????????????????? read(key);
??????????????? }

??????????? }

??????? }
??? }
??? /**
???? * 處理讀取客戶端發來的信息 的事件
???? * @param key
???? * @throws IOException
???? */
??? public void read(SelectionKey key) throws IOException{
??????? // 服務器可讀取消息:得到事件發生的Socket通道
??????? SocketChannel channel = (SocketChannel) key.channel();
??????? // 創建讀取的緩沖區
??????? ByteBuffer buffer = ByteBuffer.allocate(10);
??????? channel.read(buffer);
??????? byte[] data = buffer.array();
??????? String msg = new String(data).trim();
??????? System.out.println("服務端收到信息:"+msg);
??????? ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
??????? channel.write(outBuffer);// 將消息回送給客戶端
??? }

??? /**
???? * 啟動服務端測試
???? * @throws IOException
???? */
??? public static void main(String[] args) throws IOException {
??????? NIOServer server = new NIOServer();
??????? server.initServer(8000);
??????? server.listen();
??? }
}



package com.sohu.tv.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
* NIO客戶端
* @author 小路
*/
public class NIOClient {
??? //通道管理器
??? private Selector selector;

??? /**
???? * 獲得一個Socket通道,并對該通道做一些初始化的工作
???? * @param ip 連接的服務器的ip
???? * @param port? 連接的服務器的端口號
???? * @throws IOException
???? */
??? public void initClient(String ip,int port) throws IOException {
??????? // 獲得一個Socket通道
??????? SocketChannel channel = SocketChannel.open();
??????? // 設置通道為非阻塞
??????? channel.configureBlocking(false);
??????? // 獲得一個通道管理器
??????? this.selector = Selector.open();

??????? // 客戶端連接服務器,其實方法執行并沒有實現連接,需要在listen()方法中調
??????? //用channel.finishConnect();才能完成連接
??????? channel.connect(new InetSocketAddress(ip,port));
??????? //將通道管理器和該通道綁定,并為該通道注冊SelectionKey.OP_CONNECT事件。
??????? channel.register(selector, SelectionKey.OP_CONNECT);
??? }

??? /**
???? * 采用輪詢的方式監聽selector上是否有需要處理的事件,如果有,則進行處理
???? * @throws IOException
???? */
??? @SuppressWarnings("unchecked")
??? public void listen() throws IOException {
??????? // 輪詢訪問selector
??????? while (true) {
??????????? selector.select();
??????????? // 獲得selector中選中的項的迭代器
??????????? Iterator ite = this.selector.selectedKeys().iterator();
??????????? while (ite.hasNext()) {
??????????????? SelectionKey key = (SelectionKey) ite.next();
??????????????? // 刪除已選的key,以防重復處理
??????????????? ite.remove();
??????????????? // 連接事件發生
??????????????? if (key.isConnectable()) {
??????????????????? SocketChannel channel = (SocketChannel) key
??????????????????????????? .channel();
??????????????????? // 如果正在連接,則完成連接
??????????????????? if(channel.isConnectionPending()){
??????????????????????? channel.finishConnect();

??????????????????? }
??????????????????? // 設置成非阻塞
??????????????????? channel.configureBlocking(false);

??????????????????? //在這里可以給服務端發送信息哦
??????????????????? channel.write(ByteBuffer.wrap(new String("向服務端發送了一條信息").getBytes()));
??????????????????? //在和服務端連接成功之后,為了可以接收到服務端的信息,需要給通道設置讀的權限。
??????????????????? channel.register(this.selector, SelectionKey.OP_READ);

??????????????????? // 獲得了可讀的事件
??????????????? } else if (key.isReadable()) {
??????????????????? read(key);
??????????????? }
??????????? }
??????? }
??? }
??? /**
???? * 處理讀取服務端發來的信息 的事件
???? * @param key
???? * @throws IOException
???? */
??? public void read(SelectionKey key) throws IOException{
??????? //和服務端的read方法一樣
??? }


??? /**
???? * 啟動客戶端測試
???? * @throws IOException
???? */
??? public static void main(String[] args) throws IOException {
??????? NIOClient client = new NIOClient();
??????? client.initClient("localhost",8000);
??????? client.listen();
??? }

}


2.5.4 server處理流程
ipc.Server的主要功能是接收來自客戶端的RPC請求,經過調用相應的函數獲取結果后,返回給對應的客戶端。為此,ipc.Server被劃分成3個階段:接收請求、處理請求和返回結果。
(1)接收請求
? ? ?該階段主要任務是接收來自各個客戶端的RPC請求,并將它們封裝成固定的格式(Call類)放到一個共享隊列(callQueue)中,以便進行后續處理。該階段內部又分為建立連接和接收請求兩個子階段,分別由Listener和Reader兩種線程完成。
? ? ?整個Server只有一個Listener線程,統一負責監聽來自客戶端的連接請求,一旦有新的請求到達,它會采用輪詢的方式從線程池中選擇一個Reader線程進行處理,而Reader線程可同時存在多個,它們分別負責接收一部分客戶端連接的RPC請求,至于每個Reader線程負責哪些客戶端連接,完全由Listener決定,當前Listener只是采用了簡單的輪詢分配機制。
? ? ?Listener和Reader線程內部各自包含一個Selector對象,分別用于監聽SelectionKey.OP_ACCEPT和SelectionKey.OP_READ事件。對于Listener線程,主循環的實現體是監聽是否有新的連接請求到達,并采用輪詢策略選擇一個Reader線程處理新連接;對于Reader線程,主循環的實現體是監聽(它負責的那部分)客戶端連接中是否有新的RPC請求到達,并將新的RPC請求封裝成Call對象,放到共享隊列callQueue中。

(2)處理請求
? ? ?該階段主要任務是從共享隊列callQueue中獲取Call對象,執行對應的函數調用,并將結果返回給客戶端,這全部由Handler線程完成。
? ? ?Server端可同時存在多個Handler線程,它們并行從共享隊列中讀取Call對象,經執行對應的函數調用后,將嘗試著直接將結果返回給對應的客戶端。但考慮到某些函數調用返回結果很大或者網絡速度過慢,可能難以將結果一次性發送到客戶端,此時Handler將嘗試著將后續發送任務交給Responder線程。

(3)返回結果
? ? ?前面提到,每個Handler線程執行完函數調用后,會嘗試著將執行結果返回給客戶端,但對于特殊情況,比如函數調用返回結果過大或者網絡異常情況(網速過慢),會將發送任務交給Responder線程。
? ? ?Server端僅存在一個Responder線程,它的內部包含一個Selector對象,用于監聽SelectionKey.OP_WRITE事件。當Handler沒能將結果一次性發送到客戶端時,會向該Selector對象注冊SelectionKey.OP_WRITE事件,進而由Responder線程采用異步方式繼續發送未發送完成的結果。







本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/539337.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/539337.shtml
英文地址,請注明出處:http://en.pswp.cn/news/539337.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaSE基礎知識學習-----泛型

泛型 Java泛型是jdk1.5的一個新特性&#xff0c;jdk的性特性還包括&#xff1a;泛型&#xff0c;枚舉&#xff0c;裝箱和拆箱&#xff0c;可變參數等。這里先主要學習泛型。這些特性&#xff0c;現在都在廣泛的使用。因為現在使用IDE編寫代碼&#xff0c;都是標準的代碼提示&am…

centos7 校正linux系統時間_Linux系統:Centos7下搭建ClickHouse列式存儲數據庫

一、ClickHouse簡介1、基礎簡介Yandex開源的數據分析的數據庫&#xff0c;名字叫做ClickHouse&#xff0c;適合流式或批次入庫的時序數據。ClickHouse不應該被用作通用數據庫&#xff0c;而是作為超高性能的海量數據快速查詢的分布式實時處理平臺&#xff0c;在數據匯總查詢方面…

html調用js頁面顯示不出來了,JS代碼文件調用顯示亂碼,直接寫在html頁面的里可以調用,但是單獨放在js文件里不能調用...

最近遇到了一個很奇怪的問題&#xff0c;就是在HTML網頁代碼里直接寫JS代碼可以正常運行的代碼&#xff0c;使用JS文件調用就不行。var cities [ {"name" : "北京"}, {"name" : "上海"}, {"name" : "廣州"} ];$(…

水系圖一般在哪里找得到_城市供水系統防護體系的探索與思考

城市是一個國家或地區的政治、經濟和文化中心&#xff0c; 在戰爭中常常被選為重點打擊目標。1988年&#xff0c;時任美國空軍司令部副參謀長助理的約翰A. 沃登上校提出“五環”目標打擊理論&#xff0c;將 對敵打擊目標分為五個層&#xff0c;其中就將基礎設施列為第三層打擊目…

Hadoop webHDFS設置和使用說明

原文&#xff1a;http://blog.csdn.net/iloveyin/article/details/28264027 ---------------------------------------------------------------------------------------- 1.配置 namenode的hdfs-site.xml是必須將dfs.webhdfs.enabled屬性設置為true&#xff0c;否則就不能使…

CES 2017前瞻之AI:無人機依舊小巧,機器人主打家庭服務

再過2天&#xff0c;CES 2017就要開始了&#xff0c;根據這些已知曉的部分展商&#xff0c;我們也許能夠看到未來的一些趨勢。 還有2天&#xff0c;備受矚目的CES 2017&#xff08;2017年國際消費類電子產品展覽會&#xff09;就要拉開帷幕了。 每一年&#xff0c;CES上都會出…

ionic html5 上傳圖片,ionic4+angular7+cordova上傳圖片功能的實例代碼

前言ionic是一個垮平臺開發框架&#xff0c;可通過web技術開發出多平臺的應用。但只建議開發簡單應用。復雜的應用需要用到許多cordova插件&#xff0c;而cordova插件的更新或者移動平臺的更新很可能導致插件的不可用&#xff0c;維護升級成本較高。安裝插件安裝插件Image Pick…

HDFS體系結構

Namenode 是整個文件系統的管理節點。它維護著整個文件系統的文件目錄樹&#xff0c;文件/目錄的元信息metadate和每個文件對應的數據塊列表。 功能&#xff1a;接收用戶的操作請求。 metadate信息包括&#xff1a; 1、文件的owership和permission。 2、文件包含哪些block塊…

為什么要將html頁面和樣式表分離,0031 如何使用css文件對網頁內容和樣式進行分離...

原標題&#xff1a;0031 如何使用css文件對網頁內容和樣式進行分離上節課&#xff0c;學習了針對文字可以設置很多種樣式。這節課&#xff0c;學習如何將內容和樣式進行分離。上節課的課后練習1.將斜體字體效果去除2.將工作經歷和工作經驗(部分)這2行文字也做成簡介這行文字的效…

redis 關系數據庫怎么轉換 和_redis數據庫設計(轉)

閱讀目錄redis是什么redis就是一個存儲key-value鍵值對的倉庫&#xff0c;如何使用redis在于如何理解你需要設計的系統的E-R的模型&#xff0c;然后合理的規劃redis的數據庫結構場景我舉一個簡單的消息系統的例子&#xff0c;業務需求&#xff1a;服務器端發送消息給用戶E-R模型…

Hadoop Archives

介紹 時間&#xff1a; Hadoop Archives (HAR files)是在0.18.0版本中引入的。 作用&#xff1a; 將hdfs里的小文件打包成一個文件&#xff0c;相當于windows的zip&#xff0c;rar。Linux的 tar等壓縮文件。把多個文件打包一個文件。 意義&#xff1a; 它的出現就是為了緩…

js 判斷日期時間差

2019獨角獸企業重金招聘Python工程師標準>>> alert(GetDateDiff("2018-02-27 19:20:22","2018-02-27 09:20:22","hour"));function GetDateDiff(startTime, endTime, diffType) {//將xxxx-xx-xx的時間格式&#xff0c;轉換為 xxxx/xx…

python 圖形_Python圖形數據

CSGraph代表 壓縮稀疏圖 &#xff0c;它著重于基于稀疏矩陣表示的快速圖算法。 圖表表示 首先&#xff0c;讓我們了解一個稀疏圖是什么以及它在圖表示中的作用。 什么是稀疏圖&#xff1f; 圖形只是節點的集合&#xff0c;它們之間有鏈接。圖表幾乎可以代表任何事物 - 社交網絡…

本地運行hadoop-Failed to locate the winutils binary in the hadoop binary path

轉自&#xff1a;http://www.cnblogs.com/zq-inlook/p/4386216.html 之前在mac上調試hadoop程序&#xff08;mac之前配置過hadoop環境&#xff09;一直都是正常的。因為工作需要&#xff0c;需要在windows上先調試該程序&#xff0c;然后再轉到linux下。程序運行的過程中&#…

dubbo 支持服務降級嗎_dubbo面試題!會這些,說明你真正看懂了dubbo源碼

整理了一些dubbo可能會被面試的面試題&#xff0c;感覺非常不錯。如果你基本能回答說明你看懂了dubbo源碼&#xff0c;對dubbo了解的足夠全面。你可以嘗試看能不能回答下。我們一起看下有哪些問題吧&#xff1f;dubbo中"讀接口"和"寫接口"有什么區別?談談…

不滿足于汽車制造,豐田展示仿鋼鐵俠機器支撐腿架

而汽車制造商開發機器人也不是豐田一家的專利&#xff0c;此前現代也推出過類似的支撐機器人腿架 大多數人對于豐田的印象都停留在汽車制造上&#xff0c;不過他們卻不僅僅滿足于汽車事業的發展&#xff0c;最近&#xff0c;豐田正在研發一款機器人支撐腿架&#xff0c;來幫助…

js html異步加載的屬性,異步加載JS的五種方式

方案一&#xff1a;點評&#xff1a;HTML5中新增的屬性&#xff0c;Chrome、FF、IE9&IE9均支持(IE6~8不支持)。此外&#xff0c;這種方法不能保證腳本按順序執行。方案二&#xff1a;點評&#xff1a;兼容所有瀏覽器。此外&#xff0c;這種方法可以確保所有設置defer屬性的…

python中各操作符的優先級_Python3練習題系列(06)——各種符號總結

Python3中的各種符號總結 1關鍵字 import keyword print(keyword.kwlist, end\t) [False, None, True, and, as, assert, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, r…

hdfs java讀寫hdfs demo

windows環境配置&#xff1a; 1.下載winutils的windows版本 GitHub上&#xff0c;有人提供了winutils的windows的版本&#xff0c; 項目地址是&#xff1a;https://github.com/srccodes/hadoop-common-2.2.0-bin,直接下載此項目的zip包&#xff0c;下載后是文件名是hadoop-comm…

cesium 經緯度繪制點_NCL繪制2016年1號臺風(Nepartak)

begin ncol 6 ;臺風參數 nrow 31 ;時次總數 nbin 6 ;已知該該氣旋共經歷了6個等級的演變 ;讀入臺風資料 data asciiread("NEPARTAK.txt",(/nrow,ncol/),"integer") ;/31,6/ 31行6列&#xff0c;integer整數類型 ;;數據讀取函數總結&…