[Góc suy ngẫm] Tâm thư mừng Microsoft 40 tuổi của Bill Gates

Nhà sáng lập Microsoft Bill Gates nhắc chuyện quá khứ để hướng đến tương lai trong thư gửi nhân viên của hãng nhân kỉ niệm 40 năm thành lập.


Hôm nay 4/4, hãng phần mềm lớn nhất thế giới Microsoft mừng sinh nhật lần thứ 40.
Microsoft được Bill Gates và Paul Allen thành lập năm 1975 sau khi bỏ học đại học và ngày nay đã trở thành một công ty danh tiếng với 125.000 nhân viên.
Các phần mềm của hãng hiện được cài đặt trên 90% số máy tính toàn cầu, và Microsoft là một trong ba công ty giá trị nhất thế giới, chỉ sau đại gia dầu khí Exxon Mobil và Apple.
Nhân dịp này, Bill Gates đã có thư gửi toàn thể nhân viên Microsoft, bày tỏ sự lạc quan của ông về việc hãng sẽ tiếp tục tiến xa trong thập niên tới cùng sự phát triển vũ bão của công nghệ.
Toàn văn bức thư như sau:
Ngày mai là một ngày đặc biệt: Microsoft mừng kỉ niệm 40 năm!
Trước đây, Paul Allen và tôi đặt mục tiêu làm ra một chiếc máy tính có mặt trên mọi bàn làm việc và trong mỗi căn nhà. Đó là một ý tưởng táo bạo và rất nhiều người nghĩ chúng tôi mất trí mới có thể nghĩ ra một điều không tưởng như thế.
Giờ đây, thật tuyệt vời khi nhìn lại để thấy điện toán đã phát triển như thế nào từ ngày ấy, và chúng ta đều có thể tự hào về vai trò của Microsoft trong sự phát triển này.
Tuy vậy, hôm nay tôi nghĩ nhiều về tương lai của Microsoft hơn là quá khứ. Tôi tin rằng điện toán sẽ còn phát triển trong 10 năm tới với tốc độ nhanh hơn trước đây. Chúng ta hiện đang sống trong thế giới đa nền tảng và điện toán sẽ còn mang tầm ảnh hưởng hơn nữa.
Chúng ta đang đến gần hơn thời điểm mà máy vi tính và robot có thể nhìn thấy, cử động và tương tác một cách tự nhiên, mở đường cho nhiều ứng dụng và trao cho con người nhiều khả năng hơn nữa.
Dưới sự lãnh đạo của Satya, Microsoft hơn bao giờ hết đã khẳng định vị thế là người dẫn đầu trong các tiến bộ công nghệ.
Chúng ta có đủ nguồn tài nguyên để thúc đẩy và giải quyết các vấn đề. Chúng ta có mặt tại tất cả các lĩnh vực của điện toán hiện đại và có cam kết sâu sắc nhất để nghiên cứu trong ngành này.
Với tư cách là cố vấn công nghệ cho Satya, tôi tham gia đánh giá các sản phẩm mới và thật sự ấn tượng với những tầm nhìn và tài năng tôi trông thấy. Điều này được thể hiện qua các sản phẩm như Cortana, Skype Translator, và HoloLens - và thật ra đây chỉ là một số trong rất nhiều phát kiến mới đang được thực hiện.
Trong những năm tới, Microsoft có cơ hội tiếp cận với nhiều người và các tổ chức trên khắp thế giới hơn nữa. Công nghệ vẫn còn nằm ngoài tầm với của nhiều người vì phức tạp hay đắt đỏ, hay đơn giản chỉ vì họ không thể tiếp cận chúng.
Vì thế tôi hi vọng các bạn sẽ nghĩ về việc mình có thể làm gì để tất cả mọi người đều có thể tiếp cận sức mạnh của công nghệ, kết nối mọi người với nhau và làm cho điện toán cá nhân có mặt ở khắp nơi.
Chúng ta đã cùng nhau đạt được nhiều thành tựu trong 40 năm qua và giúp vô số doanh nghiệp và người dùng phát huy hết tiềm năng của họ. Nhưng vấn đề quan trọng nhất giờ đây là chúng ta sẽ làm gì tiếp theo.
Cảm ơn các bạn đã đưa Microsoft thành một công ty tuyệt vời ngay lúc này và nhiều thập niên tới nữa.

Theo Tuổi Trẻ - NSS.

Chữa bài tập Lập trình Assembly (23-11-12)

Chữa bài tập Lập trình Assembly (23-11-12)
Bài tâp: Nhập vào 3 số a,b,c (<10). In ra màn hình số lớn nhất trong 3 số vừa nhập
;--------------------------------------
.model small
.code    
org 100h

jmp Max

    a db ?
    b db ? 
    c db ?
    tb1 db 'Nhap a: $'
    tb2 db 'Nhap b: $'
    tb3 db 'Nhap c: $'
    tb4 db 'So lon nhat la: $'
    xd db 13,10,'$'


Max proc
    ;in tb1
    mov ah,09
    lea dx,tb1
    int 21h
    
    ; Nhap a
    mov ah,01
    int 21h 
    sub al,30h
    mov a,al
    
    ;in xuong dong
    mov ah,09
    lea dx,xd
    int 21h
    
    
    ;in tb2
    mov ah,09
    lea dx,tb2
    int 21h
    
     ; Nhap b
    mov ah,01
    int 21h 
    sub al,30h
    mov b,al
      
    ;in xuong dong
    mov ah,09
    lea dx,xd
    int 21h  
        
   
    ;in tb3
    mov ah,09
    lea dx,tb3
    int 21h
    
     ; Nhap b
    mov ah,01
    int 21h 
    sub al,30h
    mov c,al
      
    ;in xuong dong
    mov ah,09
    lea dx,xd
    int 21h  
    
    
 ; tim max
    ;so sach a voi b
    mov bl,a
    cmp bl,b
    jg a_lon_hon
    jmp a_nho_hon
    
    ; neu a > b
    
    a_lon_hon:
        mov bl,a
        cmp bl,c
        jg  a_la_max
        jmp c_la_max
    
    ; neu a<=b    
    a_nho_hon:
        mov dl,b
        cmp bl,c
        jg b_la_max
        jmp c_la_max
        
    ; neu a la max, in ra a
    a_la_max:
         
        ;in tb4
        mov ah,09
        lea dx,tb4
        int 21h   
                
        mov dl,a
        add dl,30h
        mov ah,02
        int 21h
        jmp thoat
    
    ; neu b la max, in ra b
    b_la_max:    
       ;in tb4
        mov ah,09
        lea dx,tb4
        int 21h   
        
        mov dl,b  
        add dl,30h
        mov ah,02
        int 21h
        jmp thoat
       
     ; neu c la max, in ra c
    c_la_max:    
       ;in tb4
        mov ah,09
        lea dx,tb4
        int 21h   
        
        mov dl,c  
        add dl,30h
        mov ah,02
        int 21h
        jmp thoat  
    
    thoat:
    ; thoat              
    int 20h              
        
    
Max endp
;------------------------------------------------------------------------------

----------


Cùng bạn tự học CNTT - tailieucntt.org

[ C\C++ ] Ví dụ mảng 2 chiều trong C\C++

[ C\C++ ] Ví dụ mảng 2 chiều trong C\C++

/*
Vi du 1 [ mang 2 chieu ]
 - Nhap vao tu ban phim ma tran vuong chua cac so nguyen co kich thuoc n (3<=n<=8)
 - In ma tran vua nhap
 - Dem so chan trong ma tran
 - Tinh tong theo dong cua ma tran
 - Tim so lon nhat, nho nhat tron ma tran
 - In ra vi tri xuat hien cac so nguyen to trong ma tran

*/
#include<iostream.h>
#include<conio.h>
// khai bao ma tran
int a[8][8],n;
// nhap ma tran
 void Nhap(){ 
 // nhap n 
  do{  
   cout<<"\n n= "; 
   cin>>n;  
   if(n<3||n>8) 
      cout<<"\n Nhap lai n!"; 
 }while(n<3||n>8); 

// Nhap ma tran 

cout<<"\n Nhap ma tran: "; 

for(int i=0;i<n;i++)  
   for(int j=0;j<n;j++) 
    {  
      cout<<"\n a["<<i<<"]["<<j<<"]= ";  
      cin>>a[i][j]; 
    }
   }

// In ma tran
void InMaTran(){ 
  cout<<"\n IN MA TRAN VUA NHAP: \n"; 
  for(int i=0;i<n;i++) {  
    for(int j=0;j<n;j++) 
      cout<<a[i][j]<<"\t";  cout<<"\n"; 
    }
   }

// Dem so phan tu chan trong ma tran
int DemSoChan(){ 
  int d=0; for(int i=0;i<n;i++)  
     for(int j=0;j<n;j++) 
       if(a[i][j]%2==0) 
         d++;  
    return d;
 }

// Tinh tong dong
void TongDong(){ 
 cout<<"\n Tong theo dong cua ma tran: \n"; 
  int s; 
  for(int i=0;i<n;i++) {  
   s=0;  
   for(int j=0;j<n;j++)  
      s=s+a[i][j];  
      cout<<"\n Tong dong "<<i<<" : "<<s;  
  }
 }

// Ham kiem tra so nguyen to
int TestSoNT(int a){ 
  for(int i=2;i<a;i++)  
     if(a%i==0) return 0;
 return 1; 
} 

// In ra vi tri so nguyen to
void ViTriSoNT(){  
 cout<<"\n VI TRI CAC SO NGUYEN TO TRONG MA TRAN: \n";  
 for (int i=0;i<n;i++)  
   for(int j=0;j<n;j++)
     if(TestSoNT(a[i][j])==1)
       cout<<"["<<i<<"]["<<j<<"] ;";
}

// ham chinh

void main(){  
clrscr();  
Nhap(); 
InMaTran();  
cout<<"\n So so chan trong ma tran: "<<DemSoChan();  
TongDong();  
ViTriSoNT();  
getch();

}

[Tải Code Chương trình tại đây (Lưu ý: Sau 5s, click Bỏ qua quảng cáo - Skin Ad)]

[Google App Engine] Giới thiệu Google App Engine và hướng dẫn cài đặt [Công nghệ điện toán đám mây]

I. GIỚI THIỆU GOOGLE APP ENGINE

1. KHÁI NIỆM VÀ SỰ RA ĐỜI

   Trước khi đi vào phần giới thiệu về Google App Engine, chúng ta cần làm rõ khái niệm điện toán đám mây. Điện toán đám mây (Cloud Computing, hay còn biết đến với tên gọi “Điện toán máy chủ ảo”) là môi trường tính toán dựa trên Internet mà ở đó tất cả phần mềm, dữ liệu, tài nguyên được cung cấp cho máy tính và các thiết bị khác theo nhu cầu.

Thuật ngữ “đám mây” ở đây là lối nói ẩn dụ chỉ mạng Internet và như một liên tưởng về độ phức tạp của các cơ sở hạ tầng chứa trong nó.
Nói một cách đơn giản nhất, ứng dụng điện toán đám mây chính là những ứng dụng trực tuyến trên Internet. Trình duyệt là nơi ứng dụng hiện hữu và vận hành còn dữ liệu được lưu trữ và xử lý ở máy chủ của nhà cung cấp ứng dụng đó.

Một số nền tảng điện toán đám mây hiện nay: Google App Engine, Windows Azure, Amazone Webservice, Sun Cloud, Facebook, …

Google App Engine (App Engine hay GAE) là một nền tảng điện toán đám mây của Google để phát triển và lưu trữ ứng dụng web trong những trung tâm dữ liệu do Google quản lý (google-managed data centers). Bản beta được giới thiệu lần đầu tiên vào ngày 7 tháng 4 năm 2008.

GAE là 1 dịch vụ lưu trữ các ứng dụng web. Khi nói đến “ứng dụng web”, chúng ta muốn nói tới các ứng dụng hay dịch vụ được truy cập trên các trang web, thường là thông qua trình duyệt web: những trang web mua bán, mạng xã hội, … App Engine cũng có thể phục vụ các trang web truyền thống như xử lý văn bản hay hình ảnh nhưng được thiết kế dành cho thời gian thực.

Thực ra, GAE được thiết kế để lưu trữ những ứng dụng và phục vụ nhiều người dùng một cách đồng thời. Khi một ứng dụng có thể phục vụ nhiều người dùng một cách đồng thời mà không làm giảm hiệu suất, chúng ta gọi đó là sự co giãn (scales). Những ứng dụng được viết cho App Engine sẽ được co giãn một cách tự động. Càng nhiều người sử dụng chương trình, App Engine sẽ tạo ra càng nhiều tài nguyên cho ứng dụng đó và quản lý chúng. Chính bản thân ứng dụng cũng không cần phải biết đến các tài nguyên mà nó đang sử dụng.

Không như những server cung cấp các dịch vụ lưu trữ thông thường hay các server có chức năng tự quản lý, với Google App Engine, chúng ta chỉ phải trả tiền cho những tài nguyên mà chúng ta sử dụng. Những tài nguyên này được đo bằng gigabyte và không có bất kì lệ phí hàng tháng nào hay lệ phí để chúng ta thay đổi diện mạo trang web. Hóa đơn thanh toán những nguồn tài nguyên này bao gồm CPU chúng ta sử dụng, lưu trữ hàng tháng, băng thông vào ra (incoming and outgoing bandwidth), và một số các tài nguyên khác của dịch vụ App Engine.

Để giúp chúng ta có thể làm quen với GAE, mỗi lập trình viên sẽ có khoảng 500 MB lưu trữ, một lượng tài nguyên miễn phí đủ để chạy những ứng dụng nhỏ với băng thông thấp. Google dự toán rằng với nguồn tài nguyên miễn phí, một ứng dụng có thể đạt tới 5 triệu lượt truy cập trong một tháng.

2. KIẾN TRÚC HOẠT ĐỘNG

Kiến trúc của App Engine khác với những Server lưu trữ ứng dụng Web thông thường. Ở phần lõi của nó, App Engine sẽ hạn chế những truy cập từ ứng dụng của chúng ta đến cơ sở hạ tầng vật lý, ngăn cản chúng ta từ việc mở các Socket, chạy các tiến trình ngầm, hay các cách đi khác bằng cổng sau để giúp chương trình của ta có quyền trên môi trường này. App Engine được thiết kế để giải quyết mối quan tâm của chúng ta về sự mở rộng và độ tin cậy. Nó được xây dựng dựa trên khái niệm có thể mở rộng theo chiều ngang, nghĩa là thay vì ứng dụng của chúng ta sẽ được chạy trên một phần cứng mạnh mẽ, thì nó có thể chạy trên nhiều phần cứng yếu hơn.


Chúng ta có thể thấy ứng dụng App Engine đang chạy như một thực thể cô lập trong môi trường gồm nhiều thành phần (multitenant environment). App Engine chia sẻ những nguồn tài nguyên giữa các ứng dụng nhưng cô lập về dữ liệu và bảo mật giữa những thành phần với nhau. Ứng dụng của chúng ta có thể sử dụng một số các dịch vụ của Google, như là URLFetch. Bởi vì chúng ta không thể mở cổng (port) một cách trực tiếp trong ứng dụng của mình, nên chúng ta phải lệ thuộc vào dịch vụ này, ví dụ: yêu cầu Google mở cổng và thực thi ứng dụng của mình.

Xem xét kỹ hơn một chút, giả sử App Engine là một tòa nhà có gắn hệ thống điều hòa không khí và nhiệt độ. Chúng ta là một phần trong căn nhà đó (chính xác hơn là ứng dụng của chúng ta). Chúng ta không thể điều chỉnh nhiệt độ một cách trực tiếp bởi nó sẽ ảnh hưởng đến những phần khác trong tòa nhà (các ứng dụng khác). Vì vậy, chúng ta phải gửi một yêu cầu đến người chủ của căn nhà này để nhờ họ thay đổi nhiệt độ cho chúng ta. Chính xác đó là các dịch vụ của GAE như URLFetch, Bigtable query, Memcache, mail, XMPP, và các dịch vụ khác. Đó chính là bản chất những gì đang xảy ra trong App Engine.

Như vậy, trong GAE, tùy vào ứng dụng viết theo ngôn ngữ nào, nó sẽ được chạy trên môi trường Java hay Python tương ứng. Song song đó, chúng ta sẽ được cung cấp sử dụng miễn phí các dịch vụ của google như URL Fetch, Mail, Memcache, … và được lưu trữ trên cơ sở dữ liệu hướng đối tượng datastore. Khi yêu cầu được gửi lên từ phía người dùng, GAE sẽ chuyển yêu cầu đó cho ứng dụng của chúng ta. Tùy theo việc xử lý chúng mà ta cấu hình và sử dụng các ứng dụng thích hợp của GAE.

3. CÁC THÀNH PHẦN CHÍNH VÀ CHỨC NĂNG

3.1. Môi trường thực thi (runtime environment)

Một ứng dụng App Engine đáp ứng các yêu cầu web. Một yêu cầu web sẽ bắt đầu khi có một người dùng hay điển hình là các trình duyệt web của người dùng gửi một yêu cầu truy cập vào ứng dụng thông qua giao thức HTTP. Khi App Engine nhận được yêu cầu, nó sẽ xác định ứng dụng dựa vào tên miền, hoặc tên miền con của <tên bạn>.appspot.com (cung cấp miễn phí mỗi ứng dụng) hoặc là một tên miền riêng của chúng ta đã được đăng kí và thiết lập với Google Apps. App Engine lựa chọn một máy chủ từ nhiều máy chủ để xử lý các yêu cầu đó. Sau đó, App Engine sẽ gửi các yêu cầu đã nhận được từ người dùng đến ứng dụng phù hợp để xử lý, sau khi đã xử lý xong các ứng dụng này sẽ gửi dữ liệu trả về cho App Engine, App Engine sẽ nhận dữ liệu phản hồi từ các ứng dụng và trả về cho người dùng thông qua trình duyệt Web.



Google App Engine cung cấp hai môi trường thực thi tốt cho các ứng dụng. Đó là Java và Python. Môi trường chúng ta chọn sẽ phụ thuộc vào ngôn ngữ và những công nghệ liên quan khi chúng ta dùng để phát triển ứng dụng.

Môi trường Java thực thi các ứng dụng được viết cho JVM6. Ứng dụng có thể được phát triển dựa vào ngôn ngữ lập trình Java hoặc hầu hết các ngôn ngữ có thể biên dịch và chạy trên JVM: ví dụ PHP (dùng Quercus), Ruby (dùng JRuby), Javascript (dùng Rhino), Scala, Groovy. App Engine cũng hỗ trợ Google Web Tootkit (GWT).

Môi trường Python thực thi các ứng dụng được viết dựa vào ngôn ngữ lập trình Python bản 2.5. App Engine gọi các ứng dụng Python nhờ vào CGI (Common Gateway Interface). Ứng dụng có thể dùng hầu hết các thư viện của Python, các framework của Python như Django, web2py, Pylons.

Cả hai môi trường Java và Python đều sử dụng chung một mô hình: một yêu cầu gửi đến ứng dụng trên server, ứng dụng được kích hoạt (nếu cần thiết), gọi bộ phận xử lý yêu cầu và trả về kết quả cho client. Mỗi môi trường sử dụng bộ tiền xử lý (interpreter) cho riêng mình (JVM hay Python).

3.2. Các file server tĩnh (static file servers)

Hầu hết các website có một số tài nguyên mà chúng chuyển đến các trình duyệt không thay đổi trong suốt hoạt động của site. Ví dụ như các hình ảnh và các file Css hỗ trợ hiển thị của site, các đoạn mã Javascript chạy trên trình duyện, và các file HTML tĩnh. Vì việc gửi những file này không cần đến việc gọi code của ứng dụng, nói cách khác, việc này không cần thiết, làm giảm hiện quả làm việc của các server ứng dụng.

Thay vì thế, App Engine cung cấp một tập các server tách biệt chuyên làm nhiệm vụ trao đổi các file tĩnh này. Những server nói trên tối ưu hóa cho kiến trúc bên trong và hạ tầng mạng để xử lý các requests cho các tài nguyên tĩnh. Đối với client, các file tĩnh này cũng giống như các tài nguyên khác được cung cấp bởi ứng dụng của chúng ta.

Chúng ta upload các file tĩnh cùng với code ứng dụng. Chúng ta có thể cấu hình vài cách hiển thị nhất định cho các file này, bao gồm các URL cho file tĩnh, loại nội dung, và các hướng dẫn cho trình duyệt để lưu các bản sao file này trong bộ nhớ cache để giảm lưu lượng và tăng tốc cho trang Web.

3.3. Kho dữ liệu (datastore)

Hầu hết mọi ứng dụng web đều cần một nơi để chứa thông tin khi xử lý yêu cầu từ phía client và lấy thông tin cho những lần yêu cầu sau này. Việc sử dụng một server làm một trung tâm dữ liệu là một ý tưởng rất hay nhưng có vấn đề xảy ra khi quá nhiều kết nối được gửi tới server này.

Hệ thống database của Google App Engine gần giống như một đối tượng database. Thiết kế của App Engine datastore chỉ là trừu tượng để cho App Engine có thể xử lý việc phân tán và co giãn các ứng dụng. Chính vì thế trong các đoạn mã của chúng ta sẽ quan tâm đến những thứ khác được nêu sau đây.

3.3.1 Thực thể (entities) và Thuộc tính (properties)

Một ứng dụng App Engine có thể chứa dữ liệu trong một hay nhiều thực thể datastore. Mỗi thực thể có một hay nhiều thuộc tính, mỗi thuộc tính đều có tên và giá trị. Mỗi thực thể đều được phân loại để tiện cho việc truy vấn.

Ở cái nhìn đầu tiên, chúng ta thấy thực thể có thể gần giống các hàng (row) trong một bảng trong cơ sở dữ liệu quan hệ. Và mỗi thuộc tính có thể giống với một cột. Tuy nhiên đối với các thực thể cùng loại với nhau có thể có các thuộc tính khác nhau. Thứ 2, các thực thể có thể có cùng thuộc tính với các thực thể cùng loại khác nhưng khác về kiểu dữ liệu. Một điểm khác nhau nữa giữa thực thể và các hàng (row) là các thực thể có thể có nhiều giá trị cho một thuộc tính đơn lẻ.

Mỗi thực thể có một khóa riêng (key) phân biệt lẫn nhau được cung cấp bởi ứng dụng hoặc do App Engine. Khác với CSDL quan hệ, khoá của thực thể không phải là thuộc tính, nó tồn tại độc lập với thực thể. Khoá của thực thể không được thay đổi khi thực thể đã được tạo ra.

3.3.2 Truy vấn (queries) và Chỉ mục (indexes)

Một câu truy vấn trên datastore trả về không hoặc nhiều thực thể cùng loại với nhau. Nó cũng có thể trả về các khóa của thực thể. Câu truy vấn có thể dựa vào các giá trị thuộc tính của thực thể và được sắp xếp theo giá trị của thuộc tính. Câu truy vấn cũng có thể làm việc với các khóa của thực thể.

Với App Engine, mỗi câu truy vấn sẽ có một chỉ mục trong datastore. Khi ứng dụng cần thực hiên một câu truy vấn, thì datastore sẽ tìm chỉ mục của câu truy vấn đó. Khi chúng ta tạo mới một thực thể và cập nhật cái cũ thì datastore cũng sẽ cập nhật lại chỉ mục. Điều này giúp cho câu truy vấn được nhanh hơn.

3.3.3 Phiên giao dịch (transaction)

Khi một ứng dụng có quá nhiều client liên tục đọc hay ghi cùng một dữ liệu ở cùng một thời điểm, thì phiên giao dịch rất cần thiết để dữ liệu không bị đọc sai. Mỗi phiên giao dịch là đơn vị nhỏ nhất và chỉ có hai trạng thái là thành công hoặc thất bại.

Một ứng dụng đọc hay cập nhật nhiều thực thể trong một phiên giao dịch, nhưng nó phải nói cho App Engine biết những thực thể nào sẽ được cập nhật khi nó tạo ra nhiều thực thể. Ứng dụng làm được điều này bởi việc tạo ra nhóm thực thể. Nhờ nhóm thực thể, App Engine sẽ biết được các thực thể sẽ phân tán như thế nào qua các server, vì thế nó có thể khẳng định chắc chắn là phiên giao dịch thành công hay thất bại. App Engine cũng hỗ trợ những phiên giao dịch nội bộ (local transaction).

Nếu một người dùng cố gắng cập nhật một thực thể trong khi người khác đang cập nhật thực thể đó thì datastore sẽ ngay lập tức trả về một biệt lệ báo lỗi. Trong thuật ngữ database, thì ta nói App Engine sử dụng “optimistic concurrency control”. Với chỉ mục và “optimistic concurrency control”, App Engine được thiết kế giúp cho ứng dụng có thể đọc dữ liệu nhanh hơn và đảm bảo hơn.

3.4 Các dịch vụ (services)

Dịch vụ chính là mối quan hệ giữa datastore với môi trường thực thi. GAE bao gồm một số các dịch vụ hữu ích cho các ứng dụng web.

Dịch vụ memcache là dịch vụ lưu trữ theo khóa - giá trị. Thuận lợi chính của dịch vụ này trên datastore là tốc độ nhanh, rất nhanh so với việc lưu trữ và lấy dữ liệu một cách bình thường trên datastore. Memcache lưu trữ dữ liệu trên bộ nhớ thay vì trên ổ đĩa để tăng tốc độ truy cập. Nó cũng phân tán như datastore tuy nhiên không lưu trữ, vì thế nếu mất điện thì dữ liệu trên memcache cũng mất. Và nó cũng có nhiều giới hạn sử dụng hơn datastore. Việc sử dụng memcache tốt nhất là lưu lại các kết quả của các câu query hay các tính toán trước đó. Ứng dụng sẽ kiểm tra trong memcache, nếu không có dữ liệu thì sẽ tiến hành query trên datastore.

Ứng dụng App Engine có thể truy cập các tài nguyên web khác nhờ vào dịch vụ URL Fetch. Dịch vụ này tạo ra các yêu cầu theo dạng HTTP gửi đến các server khác trên Internet như là việc tương tác với các web service khác. Vì khi ta truy cập đến server khác thời gian sẽ lâu nên URL Fetch hỗ trợ chạy ngầm bên dưới trong khi xử lý các yêu cầu khác.

Ứng dụng App Engine có thể gửi mail dựa vào dịch vụ Mail, hoặc nếu được cấu hình, nó có thể nhận được email.

Ứng dụng App Engine có thể gửi và nhận những tin nhắn đến các dịch vụ chat có sử dụng giao thức XMPP bao gồm Google Talk.

3.5 Tài khoản Google (google accounts)

Các chức năng của App Engine tích hợp trong các tài khoản của Google như Google Mail, Google Docs và Google Calendar. Chúng ta có thể sử dụng tài khoản trên Google như cho các ứng dụng của chúng ta, do đó không cần thiết lập thêm. Và nếu các người dùng của chúng ta đã có tài khoản trên Google, họ có thể đăng nhập vào ứng dụng của chúng ta với các tài khoản đó, mà không cần tạo tài khoản riêng trong ứng dụng. Tất nhiên, điều đó không bắt buộc. Chúng ta luôn có thể xây dựng hệ thống tài khoản riêng của mình, hoặc sử dụng một provider OpenID.

3.6 Các công cụ lập trình (programming tools)

Google cung cấp một số tool miễn phí cho việc phá triển ứng dụng App Engine bằng ngôn ngữ Java và Python. Chúng ta có thể download software development kit (SDK) cho ngôn ngữ tương ứng và hệ điều hành của chúng ta từ website Google. Người dùng Java có thể down SDK cho Java trong form plug-in cho Eclipse. Người dùng Python sử dụng Windows hoặc Mac OS X có thể tải SDK cho Python từ form của giao diện ứng dụng. Các SDK đó đều có file zip, sử dụng command-lines để trực tiếp tích hợp vào môi trường phát triển hoặc xây dựng hệ thống.

Mỗi SDK bao gồm một server web chạy ứng dụng của chúng ta tại máy cá nhân, đóng vai trò môi trường thực thi,kho dữ liệu và các service. Server này tự động phát hiện những thay đổi trong file source và load lại chúng nếu cần, vì thế chúng ta có thể luôn mở server trong khi đang lập trình cho ứng dụng.

Nếu chúng ta sử dụng Eclipse, chúng ta có thể chạy server cho Java trong bộ tích hợp debugger, và có thể đặt các breakpoint trong code. Chúng ta cũng có thể sử dụng Eclipse cho ứng dụng phát triển Python dùng PyDev, một nhánh mở rộng của Eclipse, bao gồm bộ debugger cho Python.

Mỗi SDK cũng bao gồm một công cụ cho việc tương tác với các ứng dụng chạy trên App Engine. Chủ yếu là sử dụng cho việc upload code lên App Engine. Chúng ta cũng có thể sử dụng tool để download các file log từ ứng dụng đang chạy, hoặc quản lý danh mục ứng dụng.

SDK Python và Java gồm một chức năng mà chúng ta có thể cài đặt trong ứng dụng cho việc truy cập có thứ tự từ xa một cách an toàn đến ứng dụng. SDK Python bao gồm các công cụ dùng cho việc xử lý dữ liệu lớn, như upload dữ liệu từ file text, và tải lượng lớn dữ liệu, hoặc sao lưu cho mục đích lưu trữ. SDK cũng có command-line shell của Python cho việc test, kiểm lỗi và thao tác với dữ liệu. (Các tool này có trong SDK cho Python, nhưng cũng làm việc với các ứng dụng Java sử dụng phiên bản Java có chức năng truy cập từ xa). Chúng ta có thể viết đoạn mã script và chương trình sử dụng chức năng truy cập từ xa cho việc vận chuyển lượng lớn dữ liệu và các biện pháp bảo trì khác.

4. HẠN CHẾ CỦA GOOGLE APP ENGINE

• App Engine hỗ trợ HTTPS đối với domain con của .appspot.com những vẫn chưa hỗ trợ đối với các domain khác.

• Hiện Google App Engine hỗ trợ 2 loại ngôn ngữ là: Python, Java

(Một số ngôn ngữ khác như PHP cũng có thể chạy được nếu cài cùng với bộ chuyển từ PHP sang Java).

• Phụ thuộc hoàn toàn vào các dịch vụ của Google.

• Microsoft, … sẽ chẳng bao giờ mua sản phẩm được xây dựng trên nền tảng của đối thủ.

• Các nhà đầu tư e ngại vì toàn bộ dữ liệu của mình đều nằm trong tay nhà cung cấp dịch vụ, dù cho đó là Google.

5. SỬ DỤNG GOOGLE APP ENGINE

Bước 1. Download, cài đặt JDK + NetBean hoặc Eclipse
+ NetBeanhttps://netbeans.org/downloads/
or Eclipse: Cài đặt eclipse Download Link: https://eclipse.org/downloads.
(bạn lưu ý chọn phiên bản phù hợp với máy tính và hệ điều hành của mình)

Bước 2. Đăng ký tài khoản Google App Engine: https://appengine.google.com.

Bước 3. Cài đặt SVN Subclipse để dùng Google Project Hosting làm nơi tập trung chứa Source Code của nhóm. 
B3.1. Download file nén: http://subclipse.tigris.org/files/documents/906/49339/site-1.10.3.zip

B3.2. Giải nén file vừa download về, cho tất cả vào thư mục [plugins] trong thư mục đã cài đặt NetBeab/Eclipse.

B3.3. Khởi động lại NetBean / Eclipse. 
Vào menu (Eclipse): Windows -> Show View -> Others , gõ SVN vào hiện ra bảng sau, chọn SVN Repositories:

Ấn OK thì sẽ thấy bảng sau, ở phần dưới của cửa sổ eclipse 
 

Click chuột phải vào khoảng trắng, chọn New -> Repositories Location
Paste địa chỉ này vào: https://svn.codespot.com/a/eclipselabs.org/cloudcomputing/trunk/

B3.4. Chọn Ok. Eclipse sẽ yêu cầu nhập username password.
Cách lấy Username Password, cho mọi người vào https://code.google.com/a/eclipselabs.org/p/cloudcomputing/source/checkout sẽ thấy thông tin như sau:
# Project members authenticate over HTTPS to allow committing changes. svn checkout https://svn.codespot.com/a/eclipselabs.org/cloudcomputing/trunk/ cloudcomputing --username tranlamson When prompted, enter your generated googlecode.com password. 


Như vậy sẽ thấy username của mình, ở đây là tranlamson, ấn vào link googlcode.com password sẽ thấy password của mình. Dùng username và password này để nhập vào khi eclipse yêu cầu nhập.

Nếu thành công thì sẽ thấy folder UploadImage như hình dưới, vừa upload folder này lên để demo 
 

Như vậy là Setup môi trường thành công. Sẽ có một tutorial giới thiệu cách sử dụng svn.

Bước 4. Tải tài liệu hướng dẫn sử dụng: Để sử dụng Google App Engine (GAE) thì tham khảo 2 nguồn chính sau: 
- http://code.google.com/appengine/docs/ (tham khảo phần java) 
- Ebook upload trên project hosting https://code.google.com/a/eclipselabs.org/p/cloudcomputing.

[http://laptrinhmaytinh.net]

[ C\C++ ] Ví dụ: nhúng Assembly trong C\C++ [ Assembly ]

Nhúng Assembly trong C\C++:

* Ví dụ 1:
  - Nhập vào số nguyên n (1<=n<=10, n chẵn)
  - Tính S=2!+4!+6!+...+n!

[Code Turbo C++]
/* Nhúng mã Assembly trong C++ */

#include<iostream.h>
#include<conio.h>

// khai bao
int n;

// Nhap n (thoa man 1 <= n <= 10, n la so chan)
void Nhap(){
  cout<<"\n - Nhap n: ";
  do{
     cout<<"\n n= "; cin>>n;
     if(n<1||n>10||n%2!=0)
         cout<<"\n Nhap lai n!";
   } while(n<1||n>10||n%2!=0);
}

// Tinh giai thua
int GiaiThua(int a){
   int gt=1;
                // for(int i=1;i<=a;i++)
                //     gt*=i;
// nhung assembly
    char a1 =(char)a;
    asm xor ax,ax    // xoa thanh ghi ax
    asm mov bl,1    // bien chi so
    Tinh:
           asm mov ax,gt     // ax=gt
           asm mul bl          // ax=ax*bl
           asm mov gt,ax     // gt=ax
           asm inc bl           // bl=bl+1
           asm cmp bl,a1     // so sanh bl voi a1
           asm jg Thoat1     // nhay neu bl > a1
           asm jmp Tinh
     
     Thoat1:
      return gt;
}


// Tinh tong s=2!+4!+6!+...+n!
int TongGT(int n){
    int tong=0;
                   // for(int i=2;i<=n;i=i+2)
                   //       tong=tong+GiaiThua(i);
     int gt;
     char j, t=(char)n;
// Nhung Assembly
     asm xor dx,dx   // xoa dx
     asm mov bh,2   // i=2
     Tinh1:
              asm mov j,bh       // j=bh
              asm mov dx,tong  // dx=tong
              gt=GiaiThua(j);
              asm add dx,gt       // dx=dx+gt
              asm mov tong,dx  // tong=dx
              asm add bh,2        // bh=bh+2
              asm cmp bh,t        // so sanh bh voi t
              asm jg Thoat2       // nhay neu bh > t
              asm jmp Tinh1

      Thoat2:
       return tong;
}

// ham chinh-----------------
void main(){
   Nhap();
   // in ket qua
   cout<<"\n - Tong S= "<<TongGT(n);
   getch();

}

[Tải chương trình về máy tại đây]
--------------------------------------------------------
* Ví dụ 2: 
 - Nhập vào ma trận vuông chứa 0/1, kích thước n (1 < n < 6)
 - In ma trận vừa nhập
 - Số lần xuất hiện của số 1
 - Kiểm tra tính đối xứng của ma trận

[Code Turbo C++]
#include<iostream.h>
#include<conio.h>

void main(){
 // khai bao
 int a[5][5],n;
 int i,j;
 // nhap n
 do{
  cout<<"\n n= "; cin>>n;
  if(n<2||n>5)
cout<<"\n Nhap lai n!";
 }while(n<2||n>5);

 // nhap ma tran
 for(i=0;i<n;i++)
  for(j=0;j<n;j++)
do{
cout<<"\n a["<<i<<"]["<<j<<"]= "; cin>>a[i][j];
if(a[i][j]!=1&&a[i][j]!=0)
cout<<"\n Nhap lai a["<<i<<"]["<<j<<"] !";
}while(a[i][j]!=1&&a[i][j]!=0);

  // in ma tran

 for(i=0;i<n;i++)
 {
for(j=0;j<n;j++)
cout<<a[i][j]<<"\t";
  cout<<"\n";
  }

/* dem so lan xuat hien cua 1 (nhung assembly) */
  // chuyen doi mang a thanh mang 1 chieu
  int a1[25];
  int k=0;
  for(i=0;i<n;i++)
for(j=0;j<n;j++)
 a1[k++]=a[i][j];
// thuc hien dem
  int size=n*n, dem=0;
  asm mov ax,0 // chua bien dem
  asm lea dx,a1
  asm mov di,dx
  asm mov bx,0
  Dem1:
 asm cmp bx,size
 asm je Thoat
 asm mov dx,[di]
 asm cmp dx, 1
 asm je bang
 asm jmp khongbang
 bang:
asm inc ax
 khongbang:
asm inc di
asm inc di
asm inc bx
asm jmp Dem1
Thoat:
 asm mov dem,ax
cout<<"\n - So lan xuat hien cua 1 :"<<dem;

/* kiem tra tinh doi xung */
  char n1=(char)n,j1;
  int t,t1,t2;
  asm mov cx,0
  for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
t=a[i][j1];
t1=a[j1][i];
asm mov ax,t1
asm mov dx,t
asm cmp ax,dx
asm jne KhacNhau
asm jmp Lap1
KhacNhau:
 asm mov cx,1
 break;
Lap1:
}

asm mov t2,cx
if (t2==0)
cout<<"\n - Ma tran doi xung !";
else
 cout<<"\n - Ma tran khong doi xung !";


 getch();
}

[Tải chương trình về máy tại đây]

Tối ưu hóa mã nguồn C\C++


Tại sao phải tối ưu mã lệnh?

Sự ra đời của các trình biên dịch hiện đại đã giúp lập trình viên cải thiện đáng kể thời gian và công sức phát triển phần mềm. Một vấn đề đáng quan tâm là xu hướng phát triển phần mềm theo hướng trực quan nhanh và tiện dụng dần làm mặt bằng kĩ năng viết mã lệnh của các lập trình viên giảm rõ rệt vì họ trông cậy hoàn toàn vào sự hỗ trợ của trình biên dịch. Khi phát triển một hệ thống phần mềm có tần suất xử lý cao, ví dụ các sản phẩm có chức năng điều phối hoạt động dây chuyền sản xuất trong nhà máy, thì bên cạnh sự hỗ trợ của một trình biên dịch mạnh còn cần đến kĩ năng tối ưu mã lệnh của lập trình viên. Kĩ năng tốt sẽ biến công việc lập trình khô khan, với các đoạn code tưởng chừng lạnh lùng trở nên sinh động. Một đoạn mã lệnh tốt sẽ tận dụng tối đa ưu điểm của ngôn ngữ và khả năng xử lý của hệ thống, từ đó giúp nâng cao đáng kể hiệu suất hoạt động của hệ thống. 

Để chương trình hoạt động tối ưu, điều đầu tiên là tận dụng những hỗ trợ sẵn có của trình biên dịch thông qua các chỉ thị (directive) giúp tối ưu mã lệnh, tốc độ và kích thước chương trình. Hầu hết các trình biên dịch phổ biến hiện nay đều hỗ trợ tốt việc tối ưu mã khi biên dịch. Tuy nhiên, để đạt được hiệu quả tốt nhất, lập trình viên cần tập cho mình thói quen tối ưu mã lệnh ngay từ khi bắt tay viết những chương trình đầu tay. Bài viết này trình bày một số gợi ý rất cơ bản và kinh nghiệm thực tế tối ưu trong lập trình bằng ngôn ngữ C/C++.

Tinh giản các biểu thức toán học

Các biểu thức toán học phức tạp khi được biên dịch có thể sinh ra nhiều mã dư thừa làm tăng kích thước và chậm tốc độ thực hiện của chương trình. Do đó khi viết các biểu thức phức tạp lập trình viên cần nhớ một số đặc điểm cơ bản sau để giúp tinh giản biểu thức:

- CPU xử lý các phép tính cộng và trừ nhanh hơn các phép tính chia và nhân.

Ví dụ:

+ Biểu thức Total = (A*B + A*C + A*D) cần 2 phép cộng và 3 phép nhân. Ta có thể nhóm các phép cộng và viết thành Total = A*(B+C+D), tốc độ tính nhanh hơn vì giảm đi một phép tính nhân. 

+ Biểu thức Total = (B/A + C/A) cần 2 phép chia có thể viết thành Total = (B+C)/A, giúp giảm đi một phép chia.

- CPU xử lý tính toán với các số nguyên (integer) chậm hơn với số thực (float, double), và tốc độ xử lý float nhanh hơn double.

- Trong một số trường hợp nhân hoặc chia số nguyên, sử dụng toán tử dời bit (bit shifting) sẽ nhanh hơn toán tử nhân chia.

Ví dụ:

Biểu thức (A *= 128) có thể tận dụng toán tử dời bit sang trái thành (A <<= 7).

Một số trình biên dịch có khả năng tối ưu mã khi biên dịch như Visual C++ 6 hoặc .Net 2003, biểu thức (A *= 128) và (A <<= 7) đều được biên dịch thành:


mov eax, A
shl eax, 7 (toán tử shl được dùng thay vì mul/imul)
mov A, eax

Ta có thể tối ưu bằng cách sử dụng mã assembly trực tiếp trong mã C/C++ như sau (xem thêm thủ thuật tận dụng thế mạnh của C/C++ bên dưới):


__asm shl A, 7; 

Tối ưu việc sử dụng biến tạm

Đối với một số biểu thức tính toán số học phức tạp, trình biên dịch thường tạo các biến tạm trong bộ nhớ để chứa kết quả tính toán và cuối cùng mới gán giá trị này cho biến kết quả. Việc sử dụng biến tạm làm giảm tốc độ tính toán do phải cấp phát vùng nhớ, tính toán và thực hiện việc gán kết quả cuối cùng. Để tránh việc sử dụng biến tạm, ta có thể thực hiện việc tách các biểu thức phức tạp thành các biểu thức nhỏ hơn, hoặc sử dụng các mẹo cho việc tính toán.

Xem một ví dụ cộng các số nguyên sau:


A = B + C

Về cơ bản, khi thực hiện biểu thức này trình biên dịch tạo một biến tạm rồi thực hiện cộng 2 giá trị B, C vào biến tạm này, cuối cùng sẽ gán kết quả cho A.

Ta có thể viết lại biểu thức trên như sau để tránh sử dụng biến tạm làm chậm việc tính toán:


A = B;
A += C;

Trong lập trình hướng đối tượng, theo thói quen đôi khi lập trình viên sử dụng các biến tạm không cần thiết như trong ví dụ sau:


int MyFunc(const MyClass &A)
{
MyClass B;
B = A;
return B.value;
}

Trong hàm trên, khi biến tạm B kiểu MyClass được khởi tạo thì constructor mặc định sẽ được thực hiện. Sau đó B được gán giá trị của biến A thông qua việc sử dụng toán tử =, khi đó copy constructor sẽ được gọi. Tuy nhiên với yêu cầu của bài toán thì việc này không cần thiết, ta có thể viết lại như sau:


int MyFunc(const MyClass &A)
{
return A.value;
}

Dưới đây là một ví dụ khác cho bài toán hoán vị giá trị 2 số nguyên A và B. Thông thường, yêu cầu này sẽ được viết như sau:


int A = 7, B = 8;
int nTemp; //biến tạm
nTemp = A;
A = B;
B = nTemp;

Tuy nhiên, bạn có thể sử dụng mẹo sau để tránh sử dụng biến tạm và tăng tốc tính toán:

+ Sử dụng toán tử XOR:


A = A^B; 
B = A^B;
A = A^B;

+ Sử dụng phép cộng, trừ


nX = nX + nY;
nY = nX - nY;
nX = nX - nY;

Bạn hãy chạy thử đoạn mã lệnh trên sẽ thấy điều bất ngờ thú vị khi bài toán hoán vị được giải quyết hết sức đơn giản.

Thủ thuật tránh sử dụng biến tạm cần áp dụng linh động tùy thuộc kiểu dữ liệu, đặc biệt các loại dữ liệu phức tạp như kiểu structure, string... có cơ chế lưu trữ và xử lý riêng. Đối với các trình biên dịch hiện đại, việc tối ưu theo cách này đôi khi không cần thiết vì trình biên dịch đã hỗ trợ sẵn cơ chế tối ưu này khi biên dịch mã lệnh.

Tối ưu các biểu thức điều kiện và luận lý

Biểu thức điều kiện là thành phần không thể thiếu ở hầu hết các chương trình máy tính vì nó giúp lập trình viên biểu diễn và xử lý được các trạng thái của thế giới thực dưới dạng các mã lệnh máy tính. Những điều kiện dư thừa có thể làm chậm việc tính toán và gia tăng kích thước mã lệnh, thậm chí có những đoạn mã có xác suất xảy ra rất thấp. Một trong những tiêu chí quan trọng của việc tối ưu các biểu thức điều kiện là đưa các điều kiện có xác suất xảy ra cao nhất, tính toán nhanh nhất lên đầu biểu thức.

Đối với các biểu thức luận lý, ta có thể linh động chuyển các biểu thức điều kiện đơn giản và xác suất xảy ra cao hơn lên trước, các điều kiện kiểm tra phức tạp ra sau.

Ví dụ: Biểu thức logic ((A || B ) && C ) có thể viết thành (C && ( A || B )) vì điều kiện C chỉ cần một phép kiểm tra TRUE, trong khi điều kiện (A || B) cần đến 2 phép kiểm tra TRUE và một phép OR (||). Như vậy trong trường hợp C có giá trị FALSE, biểu thức logic này sẽ có kết quả FALSE và không cần kiểm tra thêm giá trị (A || B).

Đối với các biểu thức kiểm tra điều kiện phức tạp, ta có thể viết đảo ngược bằng cách kiểm tra các giá trị cho kết quả không thoả trước, giúp tăng tốc độ kiểm tra.

Ví dụ: Kiểm tra một giá trị thuộc một miền giá trị cho trước.


if (p <= max && p >= min && q <= max && q >= min)
{
  //thực hiện khi thoả miền giá trị
}
else //không thoả
{
  //thực hiện khi không thoả miền giá trị
}

Có thể viết thành:
if (p > max || p < min || q > max || q < min)
{
}
else
{
}

Tránh các tính toán lặp lại trong biểu thức điều kiện

Ví dụ:


if ((mydata->MyFunc() ) < min)
{
// ...
}
else if ((mydata->MyFunc() ) > max)
{
// ...
}

Ta có thể chuyển hàm MyFunc ra ngoài biểu thức điều kiệu như sau:


int temp_value = mydata->MyFunc();
if (temp_value < min)
{
// ...
}
else if (temp_value > max)
{
// ...
}

Đối với biểu thức điều kiện dạng switch...case: nếu các giá trị cho case liên tục nhau, trình biên dịch sẽ tạo ra bảng ánh xạ (còn gọi là jump table) giúp việc truy xuất đến từng điều kiện nhanh hơn và giảm kích thước mã lệnh. Tuy nhiên khi các giá trị không liên tục, trình biên dịch sẽ tạo một chuỗi các phép toán so sánh, từ đó gây chậm việc xử lý: 

Ví dụ sau cho kết quả truy xuất tối ưu khi sử dụng switch...case:


switch (my_value){case A:...break;case B:...break;case C:...break;case D:...default:...}

Trong trường hợp các giá trị dùng cho case không liên tục, ta có thể viết thành các biểu thức if...elseif...else như sau:


switch (my_value){case A:...break;case F:...break;case T:}

Có thể viết thành: 
if (my_value == A) {// xử lý cho trường hợp A}else if (my_value == F) {// xử lý cho trường hợp F}else {// các trường hợp khác}

 Tối ưu vòng lặp

Vòng lặp cũng là một thành phần cơ bản phản ánh khả năng tính toán không mệt mỏi của máy tính. Tuy nhiên, việc sử dụng máy móc vòng lặp là một trong những nguyên nhân làm giảm tốc độ thực hiện của chương trình. Một số thủ thuật sau sẽ giúp lập trình viên tăng tốc vòng lặp của mình:

- Đối với các vòng lặp có số lần lặp nhỏ, ta có thể viết lại các biểu thức tính toán mà không cần dùng vòng lặp. Nhờ vậy tiết kiệm được khoảng thời gian quản lý và tăng biến đếm trong vòng lặp.

Ví dụ cho vòng lặp sau:


for( int i = 0; i < 4; i++ ) 
{
array =MyFunc(i);
}

có thể viết lại thành: 


array[0] = MyFunc(0); 
array[1] = MyFunc(1);
array[2] = MyFunc(2);
array[3] = MyFunc(3);

- Đối với các vòng lặp phức tạp có số lần lặp lớn, cần hạn chế việc cấp phát các biến nội bộ và các phép tính lặp đi lặp lại bên trong vòng lặp mà không liên quan đến biến đếm lặp.

Ví dụ cho vòng lặp sau: 


int students_number = 10000;
for( int i = 0; i < students_number; i++ )
{
//hàm MyFunc mất nhiều thời gian thực hiện
double sample_value = MyFunc(students_number);
CalcStudentFunc(i, sample_value);
}

Trong ví dụ trên, biến sample_value được tính ở mỗi vòng lặp một cách không cần thiết vì hàm MyFunc có thể tốn rất nhiều thời gian, ta có thể dời đoạn mã tính toán này ra ngoài vòng lặp như sau:


int students_number = 10000;
double sample_value = MyFunc(students_number);
for( int i = 0; i < students_number; i++ )
{
CalcStudentFunc(i, sample_value);
}

- Đối với vòng lặp từ 0 đến n phần tử như sau:


for( int i = 0; i < max_number; i++ )

Nên thực hiện việc lặp từ giá trị max_number trở về 0 như sau:


for( int i = max_number - 1; i >=0 ; -- i )

Vì khi biên dịch thành mã máy, các phép so sánh với 0 (zero) sẽ được thực hiện nhanh hơn với các số nguyên khác. Do đó phép so sánh ở mỗi vòng lặp là ( i >=0 ) sẽ nhanh hơn phép so sánh ( i < max_number). 

- Trong vòng lặp lớn, các toán tử prefix dạng (--i hoặc ++i) sẽ thực hiện nhanh hơn toán tử postfix (i-- hoặc i++). Nguyên nhân là do toán tử prefix tăng giá trị của biến trước sau đó trả kết quả về cho biểu thức, trong khi toán tử postfix phải lưu giá trị cũ của biến vào một biến tạm, tăng giá trị của biến và trả về giá trị của biến tạm.

Tối ưu việc sử dụng bộ nhớ và con trỏ

Con trỏ (pointer) có thể được gọi là một trong những "niềm tự hào" của C/C++, tuy nhiên thực tế nó cũng là nguyên nhân làm đau đầu cho các lập trình viên, vì hầu hết các trường hợp sụp đổ hệ thống, hết bộ nhớ, vi phạm vùng nhớ... đều xuất phát từ việc sử dụng con trỏ không hợp lý. 

- Hạn chế pointer dereference: pointer dereference là thao tác gán địa chỉ vùng nhớ dữ liệu cho một con trỏ. Các thao tác dereference tốn nhiều thời gian và có thể gây hậu quả nghiêm trọng nếu vùng nhớ đích chưa được cấp phát.

Ví dụ với đoạn mã sau:


for( int i = 0; i < max_number; i++ )
{
SchoolData->ClassData->StudentData->Array = my_value; 
}

Bằng cách di chuyển các pointer dereference nhiều cấp ra ngoài vòng lặp, đoạn mã trên có thể viết lại như sau: 

unsigned long *Temp_Array = SchoolData->ClassData->StudentData->Array;


for( int i = 0; i < max_number; i++ )
{
Temp_Array = my_value; 
}

- Sử dụng tham chiếu (reference) cho đối tượng dữ liệu phức tạp trong các tham số hàm. Việc sử dụng tham chiếu khi truyền nhận dữ liệu ở các hàm có thể giúp tăng tốc đáng kể đối với các cấu trúc dữ liệu phức tạp. Trong lập trình hướng đối tượng, khi một đối tượng truyền vào tham số dạng giá trị thì toàn bộ nội dung của đối tượng đó sẽ được sao chép bằng copy constructor thành một bản khác khi truyền vào hàm. Nếu truyền dạng tham chiếu thì loại trừ được việc sao chép này. Một điểm cần lưu ý khi sử dụng tham chiếu là giá trị của đối tượng có thể được thay đổi bên trong hàm gọi, do đó lập trình viên cần sử dụng thêm từ khóa const khi không muốn nội dung đối tượng bị thay đổi.

Ví dụ: Khi truyền đối tượng dạng giá trị vào hàm để sử dụng, copy constructor sẽ được gọi.


void MyFunc(MyClass A) //copy constructor của A sẽ được gọi
{
int value = A.value;
}

Khi dùng dạng tham chiếu, đoạn mã trên có thể viết thành:

void MyFunc(const MyClass &A) //không gọi copy constructor

{

int value = A.value;

}

- Tránh phân mảnh vùng nhớ: Tương tự như việc truy xuất dữ liệu trên đĩa, hiệu năng truy xuất các dữ liệu trên vùng nhớ động sẽ giảm đi khi bộ nhớ bị phân mảnh. Một số gợi ý sau sẽ giúp giảm việc phân mảnh bộ nhớ.

+ Tận dụng bộ nhớ tĩnh. Ví dụ: như tốc độ truy xuất vào một mảng tĩnh có tốc độ nhanh hơn truy xuất vào một danh sách liên kết động.

+ Khi cần sử dụng bộ nhớ động, tránh cấp phát hoặc giải phóng những vùng nhớ kích thước nhỏ. Ví dụ như ta có thể tận dụng xin cấp phát một mảng các đối tượng thay vì từng đối tượng riêng lẻ.

+ Sử dụng STL container cho các đối tượng hoặc các cơ chế sử dụng bộ nhớ riêng có khả năng tối ưu việc cấp phát bộ nhớ. STL cung cấp rất nhiều thuật toán và loại dữ liệu cơ bản giúp tận dụng tối đa hiệu năng của C++. Các bạn có thể tìm đọc các sách về STL sẽ biết thêm nhiều điều thú vị.

- Sau khi cấp phát một mảng các đối tượng, tránh nhầm lẫn khi sử dụng toán tử delete[] và delete: với C++, toán tử delete[] sẽ chỉ định trình biên dịch xóa một chuỗi các vùng nhớ, trong khi delete chỉ xóa vùng nhớ mà con trỏ chỉ đến, do đó có thể gây hiện tượng "rác" và phân mảnh bộ nhớ.

Ví dụ:


int *myarray = new int[50];
delete []myarray;
Với delete[], trình biên dịch sẽ phát sinh mã như sau:
mov ecx, dword ptr [myarray] 
mov dword ptr [ebp-6Ch], ecx 
mov edx, dword ptr [ebp-6Ch] 
push edx 
call operator delete[] (495F10h) //gọi toán tử delete[]
add esp,4 

Trong khi với đoạn lệnh:


int *myarray = new int[50];
delete myarray;
Trình biên dịch sẽ phát sinh mã như sau:
mov ecx, dword ptr [myarray] 
mov dword ptr [ebp-6Ch], ecx 
mov edx, dword ptr [ebp-6Ch] 
push edx 
call operator delete (495F10h) //gọi toán tử delete
add esp,4 

Sử dụng hợp lý cơ chế bẫy lỗi try...catch

Việc sử dụng không hợp lý các bẫy lỗi có thể là sai lầm tai hại vì trình biên dịch sẽ thêm các mã lệnh kiểm tra ở các đoạn mã được cài đặt try...catch, điều này làm tăng kích thước và giảm tốc độ xử lý của chương trình, đồng thời gây khó khăn trong việc sửa chữa các lỗi logic. Thống kê cho thấy các đoạn mã có sử dụng bẫy lỗi thì hiệu xuất thực hiện giảm từ 5%-10% so với đoạn mã thông thường được viết cẩn thận. Để hạn chế điều này, lập trình viên chỉ nên đặt bẫy lỗi ở những đoạn mã có nguy cơ lỗi cao và khả năng dự báo trước thấp.

Tận dụng đặc tính xử lý của CPU

Để đảm báo tốc độ truy xuất tối ưu, các bộ vi xử lý (CPU) 32-bit hiện nay yêu cầu dữ liệu sắp xếp và tính toán trên bộ nhớ theo từng offset 4-byte. Yêu cầu này gọi là memory alignment. Do vậy khi biên dịch một đối tượng dữ liệu có kích thước dưới 4-byte, các trình biên dịch sẽ bổ sung thêm các byte trống để đảm bảo các dữ liệu được sắp xếp theo đúng quy luật. Việc bổ sung này có thể làm tăng đáng kể kích thước dữ liệu, đặc biệt đối với các cấu trúc dữ liệu như structure, class...

Xem ví dụ sau: 


class Test
{
bool a;
int c;
int d;
bool b;
};

Theo nguyên tắc alignment 4-byte (hai biến "c" và "d" có kích thước 4 byte), các biến "a" và "b" chỉ chiếm 1 byte và sau các biến này là biến int chiếm 4 byte, do đó trình biên dịch sẽ bổ sung 3 byte cho mỗi biến này. Kết quả tính kích thước của lớp Test bằng hàm sizeof(Test) sẽ là 16 byte.

Ta có thể sắp xếp lại các biến thành viên của lớp Test như sau theo chiều giảm dần kích thước:


class Test
{
int c;
int d;
bool a;
bool b;
};

Khi đó, hai biến "a" và "b" chiếm 2 byte, trình biên dịch chỉ cần bổ sung thêm 2 byte sau biến "b" để đảm bảo tính sắp xếp 4-byte. Kết quả tính kích thước sau khi sắp xếp lại class Test sẽ là 12 byte. 

Tận dụng một số ưu điểm khác của C++

- Khi thiết kế các lớp (class) hướng đối tượng, ta có thể sử dụng các phương thức "inline" để thực hiện các xử lý đơn giản và cần tốc độ nhanh. Theo thống kê, các phương thức inline thực hiện nhanh hơn khoảng 5-10 lần so với phương thức được cài đặt thông thường.

- Sử dụng ngôn ngữ cấp thấp assembly: một trong những ưu điểm của ngôn ngữ C/C++ là khả năng cho phép lập trình viên chèn các mã lệnh hợp ngữ vào mã nguồn C/C++ thông qua từ khóa __asm { ... }. Lợi thế này giúp tăng tốc đáng kể khi biên dịch và khi chạy chương trình. 

Ví dụ: 


int a, b, c, d, e;
e = a*b + a*c;

Trình biên dịch phát sinh mã hợp ngữ như sau:


mov eax, dword ptr [a]
imul eax, dword ptr 
mov ecx, dword ptr [a]
imul ecx, dword ptr [c]
add eax, ecx 
mov dword ptr [e], eax

Tuy nhiên, ta có thể viết rút gọn giảm được 1 phép imul (nhân), 1 phép mov (di chuyển, sao chép):


__asm
{
mov eax, b;
add eax, c;
imul eax, a;
mov e, eax;
};

- Ngôn ngữ C++ cho phép sử dụng từ khóa "register" khi khai báo biến để lưu trữ dữ liệu của biến trong thanh ghi, giúp tăng tốc độ tính toán vì truy xuất dữ liệu trong thanh ghi luôn nhanh hơn truy xuất trong bộ nhớ.

Ví dụ:


for (register int i; i <max_number; ++i )
{
// xử lý trong vòng lặp
}

- Ngôn ngữ C/C++ hỗ trợ các collection rất mạnh về tốc độ truy xuất như các bảng map, hash_map,... nên tận dụng việc sử dụng các kiểu dữ liệu này thay cho các danh sách liên kết bộ nhớ động (linked list).

Kết luận

Một chương trình được đánh giá tốt khi tất cả các bộ phận tham gia vào hoạt động của chương trình đạt hiệu suất cao nhất theo yêu cầu của người sử dụng. Một dòng lệnh đơn giản tưởng chừng sẽ hoạt động trong tích tắc có thể làm hệ thống trở nên chậm chạp khi được gọi hàng ngàn, hàng triệu lần trong khoảng thời gian ngắn. Do vậy, trong suốt qui trình hình thành sản phẩm phần mềm, giai đoạn cài đặt mã lệnh chiếm vai trò hết sức quan trọng và cần kĩ năng tối ưu hóa cao nhất. Để đạt được điều đó, không cách nào khác hơn là lập trình viên cần tự rèn luyện thật nhiều để thông thạo ngôn ngữ mình chọn lựa, trình biên dịch mình sử dụng. Khi đó lập trình không còn là việc tạo những đoạn mã khô khan, mà là một nghệ thuật.
(Sưu tầm)

Danh mục bài viết