VBA Nâng cao: Gọi nhiều thủ tục song song cùng lúc với Excel

  • Thread starter Thread starter HeSanbi
  • Ngày gửi Ngày gửi
Liên hệ QC

HeSanbi

Nam Nhân✨Hiếu Lễ Nghĩa Trí Tín✨
Tham gia
24/2/13
Bài viết
2,692
Được thích
4,246
Giới tính
Nam
Bài viết chủ đề hôm nay tôi sẽ giới thiệu cho các bạn một cách tiếp cận mới với lập trình VBA.

Các bạn học VBA chắc chắn đa số sẽ biết rằng VBA chỉ hoạt động duy nhất một luồng cho một lớp đối tượng Application. Một số bạn mới học có thể chưa biết được điều này. Có thể hiểu đơn giản là VBA được dịch và thực thi theo thứ tự chứ không thể thực thi song song cùng một lúc nhiều lệnh.

Tuy nhiên, chúng ta vẫn có thể vượt qua giới hạn đơn luồng bằng cách khởi tạo một Lớp đối tượng Application mới ngoài tiến trình chính để phục vụ tính toán riêng biệt mà không tác động đến tiến trình chính.

Ví dụ các bạn đang cho một Macro chạy vòng lặp mười triệu, thì tất nhiên không thể gọi một Macro chạy song song trên tiến trình này được, bởi vậy buộc chúng ta phải tạo một tiến trình khác.

Để gọi được một thủ tục chạy song song chúng ta có thể thực hiện như sau:

Để bắt đầu: (Tải hai dự án ở bên dưới phần đính kèm)
Chúng ta tạo hai dự án Excel với tên MainProcess.xlsb và Process1.xlam
Dự án Process1.xlam là một bổ trợ cần được đặt trong thư mục khởi động XLSTART của Excel

Sử dụng câu lệnh để mở thư mục và tạo dự dán:

PHP:
Shell "Explorer.exe """ & Application.StartupPath & """", vbNormalFocus
Vì sao phải thực hiện như vậy? Bởi vì nếu dự án được khởi động trong thư mục đã được xác nhận quyền thì dự án sẽ được mở và khởi động Script mà không cần phải hỏi trước.

1. Khởi tạo tiến trình Excel mới:

Trong dự án MainProcess.xlsb ta sẽ đặt code để khởi tạo tiến trình với dự án Process1.xlam
Ví dụ các bạn có thể xem ở code Workbook.
Muốn mở một tiến trình mới thì trước hết chúng ta cần phải thực hiện lệnh kiểm tra xem tiến trình mới đã được mở hay chưa.
Trong Module1 sẽ có Hàm kiểm tra là IsOpenX
Khi mở tiến trình mới hãy sử dụng lệnh Cmd.exe, trong file lệnh:
PHP:
VBA.Shell "cmd.exe /S /C START ""XLProcess1"" """ & Application.Path & "\EXCEL.EXE"" /x " & XLMODE & " """ & StartupPath & "Process1.xlam""", 0
START ""XLProcess1"" - Mở ứng dụng gán tiêu đề là XLProcess1.
Đối số /x sẽ mở Excel ở tiến trình mới.
Đối số XLMODE có thể để trống hoặc là:
/safe - mở Excel ở chế độ An toàn (Safe Mode) chế độ này chỉ mở Dự án đã nhập vào
/n và /f - mở Excel.
2. Kết nối với tiến trình mới và gửi lệnh thực thi:
- Để kết nối tiến trình mới ta sử dụng hàm VBA GetObject:
Xác nhận xem File đã được mở ở tiến trình mới hay chưa thì mới thực hiện kết nối
Nếu không Hàm GetObject sẽ tự động mở file cùng tiến trình chính.
Trong file các bạn sẽ thấy dòng code VBA.GetObject(StartupPath & "Process1.xlam")
- Gửi lệnh thực thi:
File Process1.xlam sẽ nhận lệnh thực thi, nếu ta vô tình gửi lệnh trực tiếp thì tiến trình chính buộc phải đợi cho Thủ tục ở tiến trình mới thực thi xong, vì vậy ta sẽ gán các đối số vào biến trung gian và sử dụng phương thức OnTime gọi thủ tục thực thi.
Trong File Process1.xlam module1 các bạn sẽ thấy thủ tục test, nó là một thủ tục gọi gián tiếp.

-------------------
PHP:
Private Function test(Target As Range) As Boolean
  Set Main_Target = Target
  Application.OnTime VBA.Now, "'" & ThisWorkbook.Name & "'!test_Run"
End Function
-------------------

3. Ẩn cửa sổ tiến trình mới:
Các bạn có thể sử dụng hàm WinAPI ShowWindow để ẩn của sổ đi


-------------------
PHP:
Private Sub HideWindowUI()
  ShowWindow Application.hwnd, 0
End Sub

---------------------------------
Tôi khuyên các bạn lập trình sử dụng ứng dụng Rainmeter để kiểm tra CPU, RAM, Network, để tránh các rủi ro, khi test một file nào đó.

---------------------------------
FormatExcel.png

-------------------
Mặc dù hướng dẫn trên rất đơn giản, nhưng trong quá trình lập trình, sẽ có nhiều thử thách phức tạp hơn rất nhiều. Nếu các bạn có cố gắng thì sẽ thành công.


Chúc các bạn thành công!

 

File đính kèm

Lần chỉnh sửa cuối:
Nhờ bài nay mà tôi có ý tưởng xử lý trường hợp giống vậy cho trường hợp của Access. Khi ứng dụng chạy, có phần cần tải dữ liệu về thì nó mất một khoảng thời gian để chờ, không xử lý các thao tác khác (không liên quan) được. Để ngâm cứu cách thức xử lý kiểu của bạn thử xem sao. :)
 
Upvote 0
Anh nêu cụ thể xem nào, có nhiều cách mà. :)
----------------------


Anh befaint giúp chạy các Hàm WinAPI song song với nhau thử xem sao! Để mọi người tham khảo.

Như là các Hàm Callback Function này :SetTimer , CallNextHookEx ,...
 
Upvote 0
Mình không rành API đâu, dùng cách đơn giản thôi.
-----------------------

Vậy thì cách của anh không phù hợp trong trường hợp này.
Cách trên có thể tận dụng đầy đủ các hàm WinAPI.

Còn nếu ta gọi một tệp VBScript thì VBScript không có hỗ trợ WinAPI.
 
Upvote 0
Anh nêu cụ thể xem nào, có nhiều cách mà. :)

Ví dụ ở ứng Access font end, tôi mở một Form truy vấn dữ liệu từ SQL Server "Select * From Table1 Where....". Trong thời gian chờ nó lấy dữ liệu về trên Form thì tôi muốn mở cái Form khác để nhập liệu, hoặc Report khác để lấy báo cáo thì không xử lý đồng thời được.
 
Upvote 0
Ví dụ ở ứng Access font end, tôi mở một Form truy vấn dữ liệu từ SQL Server "Select * From Table1 Where....". Trong thời gian chờ nó lấy dữ liệu về trên Form thì tôi muốn mở cái Form khác để nhập liệu, hoặc Report khác để lấy báo cáo thì không xử lý đồng thời được.
Nếu vậy nảy sinh nhiều rắc rối lắm đó anh. Em cũng chạy đa luồn đây.
 
Upvote 0
Nếu vậy nảy sinh nhiều rắc rối lắm đó anh. Em cũng chạy đa luồn đây.
--------------------


Chạy đa luồng là sao bạn? Tôi chưa thấy VBA thuần hoạt động đa luồng bao giờ.
Nếu thật là VBA hoạt động đa luồng được thì bạn đúng, ngược lại có vẻ như bạn đã sử dụng thuật ngữ hơi lệch lạc.

Nếu như Vận dụng Python, C#, Delphi, LuaJit, ... thì có thể đề cập đa luồng.
 
Upvote 0
Không mình không nói trong VBA. Trong này mình pó tay. Mình đang nói tới cái chương trình mình đang viết
 
Upvote 0
--------------------


Chạy đa luồng là sao bạn? Tôi chưa thấy VBA thuần hoạt động đa luồng bao giờ.
Nếu thật là VBA hoạt động đa luồng được thì bạn đúng, ngược lại có vẻ như bạn đã sử dụng thuật ngữ hơi lệch lạc.

Nếu như Vận dụng Python, C#, Delphi, LuaJit, ... thì có thể đề cập đa luồng.
VB6 +... chạy đa luồng là chuyện thường
còn VBA thấy rất hiếm ... tham khảo link sau xem sao ??!!!
 
Upvote 0
VB6 +... chạy đa luồng là chuyện thường
còn VBA thấy rất hiếm ... tham khảo link sau xem sao ??!!!
------------------------------------

bác kieu manh có thể copy một đoạn nói VBA đa luồng trong bài viết đấy không.

Nhưng tôi đọc qua thì không thấy VBA đa luồng.

Có hai bài cuối cùng, phương pháp tương tự bài viết này. Mở tiến trình mới, chứ không phải đa luồng.
 
Upvote 0
Ví dụ ở ứng Access font end, tôi mở một Form truy vấn dữ liệu từ SQL Server "Select * From Table1 Where....". Trong thời gian chờ nó lấy dữ liệu về trên Form thì tôi muốn mở cái Form khác để nhập liệu, hoặc Report khác để lấy báo cáo thì không xử lý đồng thời được.
Nhu cầu sử dụng cao vậy mà sao không lên C# luôn nhỉ? Netframework hỗ trợ thread rất mạnh,. Thích nhất C# ở khoản mình có nhu cầu gì thì nó đều đáp ứng được hết cứ y như nó hiểu mình . Chẳng hạn:
  1. Chạy nhiều thread để giải quyết vấn đề theo nhiều hướng. Chỉ cần một hướng hoàn thành thì đóng tất cả thread (chưa xong) còn lại.
  2. Chạy nhiều thread cho mỗi tác vụ. Đợi tất cả các thread hoàn thành thì tiếp tục thực hiện các lệnh tiếp.
Nếu không dùng nhiều thread để giải quyết thì chương trình tôi sẽ tốn nhiều thời gian để thực hiện tuàn tự, kéo dài gấp vài chục lần là thường tình.
 
Upvote 0
Ai rảnh thử xem bài đó xem sao ... đang Mò Google chút... File của link trên đó
 

File đính kèm

Upvote 0
Ai rảnh thử xem bài đó xem sao ... đang Mò Google chút... File của link trên đó
------------------------------

Bác đã nhầm to "Hàng đợi" và Đa luồng nhé bác.

Trong trường hợp này gọi là "Hàng đợi" - xếp hàng chờ lệnh nha bác kieu manh:

Chứ không thể gọi là đa luồng. Trong đa luồng có sự bổ trợ bởi "hàng đợi".

Nếu bác thực hiện tính toán thì không thể nào thực hiện được bằng phương pháp này.

Trường hợp request Dữ liệu này, thì có thể vận dụng được.

Tuy nhiên bác thử chạy code 2 đến 3 lần
Vài phút sau:
CPU của bác tự động bị chiếm dụng, nhưng không biết nó tính toán cái gì.
Khoảng 30% trên Ryzen 7. thấp hơn có thể 50%-70%.
Với những bạn không rành, chuyện sớm hỏng CPU là khó tránh khỏi.

Rủi ro giết chết tiến trình rất là cao.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom