xlsgen > overview > Multi-core sample |
xlsgen supports multiple threads, one thread per document. The age of multi-core computers is particularly well suited for maximizing the speed of xlsgen scenarios.
In the following is a rather simple piece of code run in multiple threads (the number of threads is evaluated from the actual physical hardware count), that adds pseudo-random content to a spreadsheet. It is written in Java, VB.NET, C# and C++ and is available in the /samples folder of the install.
Java code |
class multicore_threads { public static class WorkerThread extends Thread { protected XlsEngine m_engine; protected boolean m_bStopped; protected String m_szFilename; WorkerThread(XlsEngine engine, String szFilename) { m_engine = engine; m_bStopped = false; m_szFilename = szFilename; } public boolean IsStopped() { return m_bStopped; } public void run() { XlsWorkbook wbk = m_engine.New(m_szFilename); XlsWorksheet wksht = wbk.AddWorksheet( "sheet1" ); int cnt = 0; for (int r = 1; r < 40000; r++) { for (int c = 1; c <= 20; c++) { wksht.putLabel(r, c * 2 + 0, "Label"); wksht.putNumber(r,c * 2 + 1, cnt++); } } wbk.Close(); m_bStopped = true; } public void destroy() { } } public static void main(String[] args) { XlsEngine engine = new XlsEngine("./../../../xlsgen.dll"); int nbThreads = Runtime.getRuntime().availableProcessors(); System.out.println("multicore sample : " + nbThreads + " threads being created (one per core)"); long startTicks = System.currentTimeMillis(); List arrThreads = new ArrayList(nbThreads); for (int i = 0; i < nbThreads; i++) { WorkerThread t = new WorkerThread(engine, "myfile" + i + ".xls"); t.start(); arrThreads.add(t); } while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { } boolean bAtLeastOneRunning = false; for (int i = 0; i < nbThreads; i++) { WorkerThread t = (WorkerThread) arrThreads.get(i); if (!t.IsStopped()) { bAtLeastOneRunning = true; break; } } if (!bAtLeastOneRunning) break; } long endTicks = System.currentTimeMillis(); long secs = (endTicks - startTicks) / 1000; System.out.println("test duration = " + secs + " seconds"); BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) ); try { br.readLine(); } catch(IOException e) { } } } |
VB.NET code |
Imports System Imports System.Threading Imports xlsgen Module Module1 Public Class WorkerThread Protected m_engine As CoXlsEngine Protected m_szFilename As String Protected m_bStopped As Boolean Sub New(ByVal engine As CoXlsEngine, ByVal szFilename As String) m_engine = engine m_szFilename = szFilename m_bStopped = False End Sub Public Function IsStopped() As Boolean IsStopped = m_bStopped End Function Public Sub Run() ' code begins here '... Dim wbk As IXlsWorkbook wbk = m_engine.New(m_szFilename) Dim wksht As IXlsWorksheet wksht = wbk.AddWorksheet("sheet1") Dim cnt = 0 For r = 1 To 40000 For c = 1 To 20 wksht.Label(r, c * 2 + 0) = "Label" wksht.Number(r, c * 2 + 1) = cnt cnt = cnt + 1 Next Next wbk.Close() m_bStopped = True End Sub End Class Public Class Program Public Shared Sub Main() Dim startTicks = DateTime.Now.Ticks Dim engine As CoXlsEngine = New CoXlsEngine Dim arrThreads As New List(Of WorkerThread) Dim nbThreads = System.Environment.ProcessorCount Console.WriteLine("multicore sample : " & nbThreads & " threads being created (one per core)") ' create worker threads ' For i = 1 To nbThreads Dim t As New WorkerThread(engine, "myfile" & i & ".xls") arrThreads.Add(t) ThreadPool.QueueUserWorkItem( _ New WaitCallback(AddressOf ThreadProc), t ) Next Console.WriteLine("Worker threads started.") ' wait for all worker threads to end ' While (True) Thread.Sleep(100) Dim bAtLeastOneRunning = False For Each t As WorkerThread In arrThreads If (t.IsStopped() = False) Then bAtLeastOneRunning = True Exit For End If Next If (bAtLeastOneRunning = False) Then Exit While End If End While Dim endTicks = DateTime.Now.Ticks Dim elapsedSpan As TimeSpan = New TimeSpan(endTicks - startTicks) Console.WriteLine("test duration = " & elapsedSpan.TotalSeconds & " seconds.") Console.WriteLine("Main thread exits.") Console.ReadLine() End Sub ' This thread procedure performs the task. Shared Sub ThreadProc(ByVal stateInfo As Object) Dim t As WorkerThread t = stateInfo t.Run() End Sub End Class |
C# code |
class WorkerThread { protected CoXlsEngine m_engine; protected String m_szFilename; protected bool m_bStopped; public WorkerThread(CoXlsEngine engine, String szFilename) { m_engine = engine; m_szFilename = szFilename; m_bStopped = false; } public bool IsStopped() { return m_bStopped; } public void Run() { // code begins here //... IXlsWorkbook wbk = m_engine.New(m_szFilename); IXlsWorksheet wksht = wbk.AddWorksheet( "sheet1" ); int cnt = 0; for (int r = 1; r < 40000; r++) { for (int c = 1; c <= 20; c++) { wksht.set_Label(r, c * 2 + 0, "Label"); wksht.set_Number(r, c * 2 + 1, cnt++); } } wbk.Close(); m_bStopped = true; } } class Program { static void Main(string[] args) { long startTicks = DateTime.Now.Ticks; CoXlsEngine engine = new CoXlsEngine(); List<WorkerThread> arrThreads = new List<WorkerThread>(); int nbThreads = System.Environment.ProcessorCount; Console.WriteLine("multicore sample : " + nbThreads + " threads being created (one per core)"); // create worker threads // for (int i = 0; i < nbThreads; i++) { WorkerThread t = new WorkerThread(engine, "myfile" + i + ".xls"); arrThreads.Add(t); ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), t); } Console.WriteLine("Worker threads started."); // wait for all worker threads to end // while (true) { Thread.Sleep(100); bool bAtLeastOneRunning = false; for (int i = 0; i < nbThreads; i++) { WorkerThread t = arrThreads.ElementAt(i); if (!t.IsStopped()) { bAtLeastOneRunning = true; break; } } if (!bAtLeastOneRunning) break; } long endTicks = DateTime.Now.Ticks; TimeSpan elapsedSpan = new TimeSpan(endTicks - startTicks); Console.WriteLine("test duration = " + elapsedSpan.TotalSeconds + " seconds."); Console.WriteLine("Main thread exits."); Console.ReadLine(); } // This thread procedure performs the task. static void ThreadProc(Object stateInfo) { WorkerThread t = (WorkerThread)stateInfo; t.Run(); } } |
C/C++ code |
::CoInitialize(NULL); SYSTEM_INFO sysinfo; ::GetSystemInfo( &sysinfo ); int nbThreads = sysinfo.dwNumberOfProcessors; TCHAR sztmp[128]; _stprintf(sztmp,"multicore sample : %d threads being created (one per core)\r\n", nbThreads); OutputDebugString(sztmp); LPUNITHREAD* coll = new LPUNITHREAD[nbThreads]; DWORD dwStart, dwEnd; { xlsgen::IXlsEnginePtr engine( __uuidof(xlsgen::CoXlsEngine) ); dwStart = ::GetTickCount(); int i; for (i = 0; i < nbThreads; i++) { TCHAR szFilename[MAX_PATH]; sprintf(szFilename, "%s%d%s", "myfile", i, ".xls"); CUnitThread* u = new CUnitThread(); if (u) { u->Start(engine, i, szFilename); coll[i] = u; } } while (1) { ::Sleep(100); bool bAtLeastOneRunning = false; for (i = 0; i < nbThreads; i++) { if (!coll[i]->IsStopped()) { bAtLeastOneRunning = true; break; } } if (!bAtLeastOneRunning) break; } dwEnd = ::GetTickCount(); for (i = 0; i < nbThreads; i++) { delete coll[i]; } delete [] coll; } DWORD dwElapsed = dwEnd - dwStart; DWORD secs = dwElapsed / 1000; _stprintf(sztmp,"test duration = %d seconds\r\n", secs); OutputDebugString(sztmp); ::CoUninitialize(); return 0; --- unitthread.h --- #pragma once class CUnitThread; typedef CUnitThread* LPUNITHREAD; class CUnitThread { // Members // protected: int m_nCnt; TCHAR m_szFilename[MAX_PATH]; xlsgen::IXlsEnginePtr m_engine; // thread mgt members DWORD m_ThreadId ; // ID of thread HANDLE m_hThread ; // Handle to thread HANDLE m_hEvent; // Handle to event HANDLE m_hComponentReadyEvent ; // Event signals thread to continue. bool m_bStopped; // Constructor // public: CUnitThread(); virtual ~CUnitThread(); // Methods // public : BOOL Start(xlsgen::IXlsEnginePtr &engine, int id, LPSTR filename); void Stop(); void Increase(); // Accessors // public: int GetCnt(); bool IsStopped(); // Internal // protected: BOOL StartThread(HANDLE hEvent) ; // Create and start the thread. BOOL IsThreadStarted() ; // Current thread status static DWORD WINAPI RealThreadProc(void* pv) ; // Thread procedure DWORD ClassThreadProc() ; // Member thread procedure BOOL WaitWithMessageLoop(HANDLE hEvent) ; // Wait for an event, but process window messages. }; --- unitthread.cpp --- #include "unitthread.h" CUnitThread::CUnitThread() { m_ThreadId = 0 ; m_hThread = NULL ; m_hComponentReadyEvent = m_hEvent = NULL ; m_bStopped = false; m_nCnt = 0; } CUnitThread::~CUnitThread() { if (m_hThread) ::TerminateThread(m_hThread,0); } BOOL CUnitThread::Start(xlsgen::IXlsEnginePtr &engine, int id, LPSTR filename) { _tcscpy(m_szFilename, filename); m_nCnt = id; m_engine = engine; return StartThread(NULL); } void CUnitThread::Stop() { } int CUnitThread::GetCnt() { return m_nCnt; } void CUnitThread::Increase() { m_nCnt++; } bool CUnitThread::IsStopped() { return m_bStopped; } /////////////////////////////////////////////////////////// // // StartThread // - Create and start the thread. // BOOL CUnitThread::StartThread(HANDLE hEvent) { if (IsThreadStarted()) { if (m_hThread) ::TerminateThread(m_hThread,0); m_hThread = NULL; } // Create the thread. m_hThread = ::CreateThread(NULL, // Default security 0, // Default stack size RealThreadProc, (void*)this, CREATE_SUSPENDED, // Create the thread suspended. &m_ThreadId) ; // Get the Thread ID. if (m_hThread == NULL) { DWORD nError = ::GetLastError(); return FALSE ; } // Create an event for the thread to signal when it is finished. m_hComponentReadyEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL) ; if (m_hComponentReadyEvent == NULL) { return FALSE ; } // store event handle passed by parent // m_hEvent=hEvent; // Thread was created suspended; start the thread. DWORD r = ResumeThread(m_hThread) ; // Wait for the thread to start up before we continue. WaitWithMessageLoop(m_hComponentReadyEvent) ; return TRUE; } /////////////////////////////////////////////////////////// // // Current thread status // BOOL CUnitThread::IsThreadStarted() { return (m_hThread != NULL) ; } /////////////////////////////////////////////////////////// // // Thread procedure // DWORD WINAPI CUnitThread::RealThreadProc(void* pv) { CUnitThread* pApartment = reinterpret_cast<CUnitThread*>(pv) ; return pApartment->ClassThreadProc() ; } void increaseCnt(CUnitThread* t) { t->Increase(); } /////////////////////////////////////////////////////////// // // Thread procedure // DWORD CUnitThread::ClassThreadProc() { // Signal that we are starting. SetEvent(m_hComponentReadyEvent) ; // code begins here //... xlsgen::IXlsWorkbookPtr wbk; wbk = m_engine->New( _bstr_t(m_szFilename) ); xlsgen::IXlsWorksheetPtr wksht; wksht = wbk->AddWorksheet( L"sheet1" ); int cnt = 0; for (int r = 1; r < 40000; r++) { for (int c = 1; c <= 20; c++) { wksht->Label[r][c * 2 + 0] = L"Label"; wksht->Number[r][c * 2 + 1] = cnt++; } } wbk->Close(); m_bStopped = true; return 0 ; } /////////////////////////////////////////////////////////// // // BOOL WaitWithMessageLoop(HANDLE hEvent) // BOOL CUnitThread::WaitWithMessageLoop(HANDLE hEvent) { while (TRUE) { // Wait for the event and for messages. DWORD dwReturn = ::MsgWaitForMultipleObjects(1, &hEvent, FALSE, INFINITE, QS_ALLINPUT) ; if (dwReturn == WAIT_OBJECT_0) { // Our event happened. ::CloseHandle(hEvent); return TRUE ; } else if (dwReturn == WAIT_OBJECT_0 + 1) { // Handle message to keep client alive. MSG msg ; while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg) ; } } else { return FALSE ; } } } |
xlsgen documentation. © ARsT Design all rights reserved.