nguyendang95
Thành viên chính thức
- Tham gia
- 25/5/22
- Bài viết
- 88
- Được thích
- 83
TwinBasic, chắc nhiều đã từng nghe nói đến, là ngôn ngữ lập trình được nhiều tín đồ VB đánh giá là ứng viên rất sáng giá thay thế cho VB6/VBA hiện nay. Mặc dù qua nhiều năm vẫn còn đang ở giai đoạn beta, tuy nhiên TwinBasic tương thích khá tốt với VB6/VBA giúp lập trình viên có thể dễ dàng chuyển đổi, ngoài ra nó còn bổ sung thêm nhiều tính năng đáng giá mà VB6/VBA còn thiếu.
Nói về khả năng lập trình đa luồng, hiện tại TwinBasic vẫn chưa có cú pháp giúp lập trình viên dễ dàng triển khai tính năng này và tác giả của ngôn ngữ lập trình này cũng hứa hẹn bổ sung cú pháp trong Quý 2 năm nay theo như ghi nhận trong Roadmap (lịch trình) đăng tải trên Github của tác giả, tuy nhiên với sự trợ giúp của các hàm Win32 API, chúng ta có thể dễ dàng viết một ứng dụng chạy đa luồng và tốn chút sức lực để gỡ lỗi và chạy thử hoàn thiện.
Code dưới đây lần lượt tạo thread, gửi http request đến các URL trong danh sách và nhận lại phản hồi từ các URL này.
Kết quả trả về đúng như mong muốn.
Liên hệ đến khả năng lập trình đa luồng khi viết COM add-in cho Excel bằng TwinBasic
TwinBasic cho phép lập trình viên viết COM add-in cho các ứng dụng Office nói chung và Excel nói riêng. Như vậy lập trình viên có thể viết code đa luồng xử lý giúp cải thiện hiệu năng tính toán cho add-in, ví dụ như trích xuất dữ liệu từ các bảng tính sau đó tạo nhiều luồng xử lý tính toán và ghi kết quả ngược lại vào bảng tính, hoặc tạo một thread mới và đưa công việc tính toán nặng nề lên đó xử lý giúp UI của Excel không bị đơ, chẳng hạn.
Với mô hình đối tượng của Excel nói riêng và các ứng dụng Office nói chung, việc này có thể hơi phức tạp do nó luôn chạy trong thread chính STA. Tham khảo bài viết từ Microsoft Threading support in Office để biết thêm thông tin chi tiết.
Nói về khả năng lập trình đa luồng, hiện tại TwinBasic vẫn chưa có cú pháp giúp lập trình viên dễ dàng triển khai tính năng này và tác giả của ngôn ngữ lập trình này cũng hứa hẹn bổ sung cú pháp trong Quý 2 năm nay theo như ghi nhận trong Roadmap (lịch trình) đăng tải trên Github của tác giả, tuy nhiên với sự trợ giúp của các hàm Win32 API, chúng ta có thể dễ dàng viết một ứng dụng chạy đa luồng và tốn chút sức lực để gỡ lỗi và chạy thử hoàn thiện.
Code dưới đây lần lượt tạo thread, gửi http request đến các URL trong danh sách và nhận lại phản hồi từ các URL này.
Mã:
Module MainModule
Private Declare PtrSafe Function CreateThread Lib "Kernel32.dll" (ByVal lpThreadAttributes As LongPtr, ByVal dwStackSize As Long, ByVal lpStartAddress As LongPtr, ByVal lpParameter As LongPtr, ByVal dwCreationFlags As Long, ByRef lpThreadId As Long) As LongPtr
Private Declare PtrSafe Function CloseHandle Lib "Kernel32.dll" (ByVal hObject As LongPtr) As Long
Private Declare PtrSafe Function WaitForSingleObject Lib "Kernel32.dll" (ByVal hHandle As LongPtr, ByVal dwMiliseconds As Long) As Long
Private Declare PtrSafe Sub CoUninitialize Lib "Ole32.dll" ()
Private Declare PtrSafe Function CreateMutex Lib "Kernel32.dll" Alias "CreateMutexW" (ByVal lpMutexAttributes As LongPtr, ByVal bInitialOwner As Long, ByVal lpName As String) As LongPtr
Private Declare PtrSafe Function ReleaseMutex Lib "Kernel32.dll" (ByVal hMutex As LongPtr) As Long
Private Declare PtrSafe Function CoInitializeEx Lib "ole32.dll" (ByVal pvReserved As LongPtr, ByVal dwCoInit As Long) As Long
Private Declare PtrSafe Function GetCurrentThreadId Lib "Kernel32.dll" () As Long
Private Mutex As LongPtr
Private Const COINIT_MULTITHREADED = &H0
Private Const COINIT_DISABLE_OLE1DDE = &H4
Private Const WAIT_OBJECT_0 = &H0
Private Const INFINITE = -1&
Private Const WAIT_ABANDONED = &H80
Private HttpResponses As New Collection(Of String)
Public Sub Main()
Mutex = CreateMutex(0, 0, vbNullString) 'Khởi tạo Mutex để sử dụng cho mục đích đồng bộ giữa các thread
If Mutex = 0 Then
Console.WriteLine("Failed to create mutex")
Exit Sub
Else: Console.WriteLine("Mutex has been created")
End If
Dim Thread As LongPtr, ThreadId As Long, i As Long
Dim Urls As Variant = Array("https://google.com.vn", "https://youtube.com", "https://x.com", "https://facebook.com")
Dim Threads(0 To 3) As LongPtr
For i = LBound(Urls) To UBound(Urls)
Thread = CreateThread(0, 0, AddressOf GetHttpResponse, VarPtr(Urls(i)), 0, ThreadId) 'Tạo thread
If Thread = 0 Then
Console.WriteLine("Failed to create thread")
CloseHandle(Mutex)
Exit Sub
End If
Threads(i) = Thread
Next
For i = LBound(Threads) To UBound(Threads)
WaitForSingleObject(Threads(i), INFINITE) 'Chờ các thread chạy xong
CloseHandle(Threads(i)) 'Dọn dẹp thread
Next
CloseHandle(Mutex) 'Dọn dẹp Mutex sau khi dùng xong
Console.WriteLine("Mutex has been destroyed")
Console.WriteLine("Number of responses: " & CStr(HttpResponses.Count)) 'Số lượng http response tiếp nhận từ các thread
End Sub
Private Sub GetHttpResponse(ByVal Url As Variant)
Dim ThreadId As Long = GetCurrentThreadId(), WaitResult As Long
Console.WriteLine("Thread Id: " & CStr(ThreadId))
'Khởi tạo COM library là MTA, thêm tùy chọn tắt tính năng OLE1DDE đã lỗi thời
CoInitializeEx(0, COINIT_MULTITHREADED Or COINIT_DISABLE_OLE1DDE)
Dim objWinHttp As WinHttp.WinHttpRequest
Set objWinHttp = New WinHttp.WinHttpRequest
With objWinHttp
.Open("GET", Url, False)
On Error Resume Next
.Send()
If Err.Number <> 0 Then
Console.WriteLine("An error occurred. " & Err.Description)
Else
If .Status = 200 Then
Console.WriteLine("Response from " & Url & " with status code " & CStr(.Status))
WaitResult = WaitForSingleObject(Mutex, INFINITE) 'Thread tiến hành chiếm dụng Mutex
If WaitResult = WAIT_OBJECT_0 Then
Console.WriteLine("Mutex acquired by thread id " & CStr(ThreadId))
HttpResponses.Add(.ResponseText) 'Mục đích chiếm dụng Mutex là nhằm buộc các thread khác phải chờ đến lượt để ghi vào biến collection
'Tránh trường hợp các thread cùng ghi vào biến collection gây sai lệch kết quả, hay còn gọi là race condition
'Dùng xong Mutex thì hoàn trả để các thread khác sử dụng
If ReleaseMutex(Mutex) <> 0 Then
Console.WriteLine("Mutex released by thread id " & CStr(ThreadId))
Else: Console.WriteLine("An error occurred while trying to release mutex from thread id " & CStr(ThreadId))
End If
ElseIf WaitResult = WAIT_ABANDONED Then Console.WriteLine(CStr(ThreadId) & " acquired an abandoned mutex")
End If
End If
End If
On Error GoTo 0
End With
CoUninitialize() 'Kết thúc sử dụng COM library
End Sub
End Module
Kết quả trả về đúng như mong muốn.
Liên hệ đến khả năng lập trình đa luồng khi viết COM add-in cho Excel bằng TwinBasic
TwinBasic cho phép lập trình viên viết COM add-in cho các ứng dụng Office nói chung và Excel nói riêng. Như vậy lập trình viên có thể viết code đa luồng xử lý giúp cải thiện hiệu năng tính toán cho add-in, ví dụ như trích xuất dữ liệu từ các bảng tính sau đó tạo nhiều luồng xử lý tính toán và ghi kết quả ngược lại vào bảng tính, hoặc tạo một thread mới và đưa công việc tính toán nặng nề lên đó xử lý giúp UI của Excel không bị đơ, chẳng hạn.
Với mô hình đối tượng của Excel nói riêng và các ứng dụng Office nói chung, việc này có thể hơi phức tạp do nó luôn chạy trong thread chính STA. Tham khảo bài viết từ Microsoft Threading support in Office để biết thêm thông tin chi tiết.