Windows 表单中的多线程
Multithreading in Windows Forms
我用我的模型算法(加密和解密)在 Windows Forms CLI 中用动态链接库(在 C++ 和 ASM 中)编写了应用程序 Caesar Cipher。我的应用程序的那部分正在运行。
这里还有一个来自Windows Forms的多线程。用户可以选择线程数 (1-64)。如果他选择 2,则要加密(解密)的消息将分为两个子字符串,这两个子字符串将分为两个线程。我想并行执行这些线程,最终减少执行时间成本。
当用户按下加密或解密按钮时,将显示加密或解密的文本和执行 C++ 和 ASM 函数的时间成本。其实一切都很好,但是大于1的线程的时间不是更小,而是更大。
有一些代码:
/*Function which concats string for substrings to threads*/
array<String^>^ ThreadEncipherFuncCpp(int nThreads, string str2){
//Tablica wątków
array<String^>^ arrayOfThreads = gcnew array <String^>(nThreads);
//Przechowuje n-tą część wiadomosci do przetworzenia
string loopSubstring;
//Długość podstringa w wiadomości
int numberOfSubstring = str2.length() / nThreads;
int isModulo = str2.length() % nThreads;
array<Thread^>^ xThread = gcnew array < Thread^ >(nThreads);
for (int i = 0; i < nThreads; i++)
{
if (i == 0 && numberOfSubstring != 0)
loopSubstring = str2.substr(0, numberOfSubstring);
else if ((i == nThreads - 1) && numberOfSubstring != 0){
if (isModulo != 0)
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring + isModulo);
else
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring);
}
else if (numberOfSubstring == 0){
loopSubstring = str2.substr(0, isModulo);
i = nThreads - 1;
}
else
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring);
ThreadExample::inputString = gcnew String(loopSubstring.c_str());
xThread[i] = gcnew Thread(gcnew ThreadStart(&ThreadExample::ThreadEncipher));
xThread[i]->Start();
xThread[i]->Join();
arrayOfThreads[i] = ThreadExample::outputString;
}
return arrayOfThreads;
}}
这里是一个片段,负责计算C++的时间:
/*****************C++***************/
auto start = chrono::high_resolution_clock::now();
array<String^>^ arrayOfThreads = ThreadEncipherFuncCpp(nThreads, str2);
auto elapsed = chrono::high_resolution_clock::now() - start;
long long milliseconds = chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
double micro = milliseconds;
this->label4->Text = Convert::ToString(micro + " microseconds");
String^ str3;
String^ str4;
str4 = str3->Concat(arrayOfThreads);
this->textBox2->Text = str4;
/**********************************/
以及工作示例:
对于输入数据:"Some example text. Some example text2."
程序会显示:"Vrph hadpsoh whaw. Vrph hadpsoh whaw2."
1个线程的执行次数:
C++ time: 31231us.
Asm time: 31212us.
2个线程的执行次数:
C++ time: 62488us.
Asm time: 62505us.
4个线程的执行次数:
C++ time: 140254us.
Asm time: 124587us.
32个线程的执行次数:
C++ time: 1002548us.
Asm time: 1000020us.
如何解决这个问题?
- 我需要这个程序结构,这是学术项目。
- 我的 CPU 有 4 个内核。
它没有更快的原因是你没有让你的线程 运行 并行。
xThread[i] = gcnew Thread(gcnew ThreadStart(&ThreadExample::ThreadEncipher));
xThread[i]->Start();
xThread[i]->Join();
这三行创建线程,启动它运行ning,然后等待它完成。你在这里没有得到任何并行性,你只是增加了生成和等待线程的开销。
如果你想从多线程中获得加速,方法是一次启动所有线程,让它们全部运行,然后收集结果。
在这种情况下,我会这样做 ThreadEncipher
(您没有向我们展示其来源,所以我在做假设)采用一个参数,该参数用作数组指数。不是让 ThreadEncipher
从 inputString
读取并写入 outputString
,而是让它读取并写入数组的一个索引。这样,每个线程都可以同时读写。在生成所有这些线程之后,您可以等待所有这些线程完成,然后您可以处理输出数组,或者由于 array<String^>^
已经是您的 return 类型,只需 return 照原样。
其他想法:
- 您在这里混合了非托管和托管对象。如果你选择一个并坚持下去会更好。由于您使用的是 C++/CLI,我建议您坚持使用托管对象。我会停止使用
std::string
,而只使用 System::String^
。
- 由于您的 CPU 有 4 个核心,您不会通过使用超过 4 个线程来获得任何加速。当 32 个线程花费的时间比 4 个长时,请不要感到惊讶,因为您正在执行 8 倍的字符串操作,并且您有 32 个线程争夺 4 个处理器内核。
您的字符串拆分代码比需要的更复杂。你那里有五个不同的案例,我必须坐下来考虑一下,以确保它是正确的。试试这个:
int totalLen = str2->length;
for (int i = 0; i < nThreads; i++)
{
int startIndex = totalLen * i / nThreads;
int endIndex = totalLen * (i+1) / nThreads;
int substrLen = endIndex - startIndex;
String^ substr = str2->SubString(startIndex, substrLen);
...
}
我用我的模型算法(加密和解密)在 Windows Forms CLI 中用动态链接库(在 C++ 和 ASM 中)编写了应用程序 Caesar Cipher。我的应用程序的那部分正在运行。
这里还有一个来自Windows Forms的多线程。用户可以选择线程数 (1-64)。如果他选择 2,则要加密(解密)的消息将分为两个子字符串,这两个子字符串将分为两个线程。我想并行执行这些线程,最终减少执行时间成本。
当用户按下加密或解密按钮时,将显示加密或解密的文本和执行 C++ 和 ASM 函数的时间成本。其实一切都很好,但是大于1的线程的时间不是更小,而是更大。
有一些代码:
/*Function which concats string for substrings to threads*/
array<String^>^ ThreadEncipherFuncCpp(int nThreads, string str2){
//Tablica wątków
array<String^>^ arrayOfThreads = gcnew array <String^>(nThreads);
//Przechowuje n-tą część wiadomosci do przetworzenia
string loopSubstring;
//Długość podstringa w wiadomości
int numberOfSubstring = str2.length() / nThreads;
int isModulo = str2.length() % nThreads;
array<Thread^>^ xThread = gcnew array < Thread^ >(nThreads);
for (int i = 0; i < nThreads; i++)
{
if (i == 0 && numberOfSubstring != 0)
loopSubstring = str2.substr(0, numberOfSubstring);
else if ((i == nThreads - 1) && numberOfSubstring != 0){
if (isModulo != 0)
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring + isModulo);
else
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring);
}
else if (numberOfSubstring == 0){
loopSubstring = str2.substr(0, isModulo);
i = nThreads - 1;
}
else
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring);
ThreadExample::inputString = gcnew String(loopSubstring.c_str());
xThread[i] = gcnew Thread(gcnew ThreadStart(&ThreadExample::ThreadEncipher));
xThread[i]->Start();
xThread[i]->Join();
arrayOfThreads[i] = ThreadExample::outputString;
}
return arrayOfThreads;
}}
这里是一个片段,负责计算C++的时间:
/*****************C++***************/
auto start = chrono::high_resolution_clock::now();
array<String^>^ arrayOfThreads = ThreadEncipherFuncCpp(nThreads, str2);
auto elapsed = chrono::high_resolution_clock::now() - start;
long long milliseconds = chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
double micro = milliseconds;
this->label4->Text = Convert::ToString(micro + " microseconds");
String^ str3;
String^ str4;
str4 = str3->Concat(arrayOfThreads);
this->textBox2->Text = str4;
/**********************************/
以及工作示例: 对于输入数据:"Some example text. Some example text2." 程序会显示:"Vrph hadpsoh whaw. Vrph hadpsoh whaw2."
1个线程的执行次数:
C++ time: 31231us.
Asm time: 31212us.
2个线程的执行次数:
C++ time: 62488us.
Asm time: 62505us.
4个线程的执行次数:
C++ time: 140254us.
Asm time: 124587us.
32个线程的执行次数:
C++ time: 1002548us.
Asm time: 1000020us.
如何解决这个问题?
- 我需要这个程序结构,这是学术项目。
- 我的 CPU 有 4 个内核。
它没有更快的原因是你没有让你的线程 运行 并行。
xThread[i] = gcnew Thread(gcnew ThreadStart(&ThreadExample::ThreadEncipher));
xThread[i]->Start();
xThread[i]->Join();
这三行创建线程,启动它运行ning,然后等待它完成。你在这里没有得到任何并行性,你只是增加了生成和等待线程的开销。
如果你想从多线程中获得加速,方法是一次启动所有线程,让它们全部运行,然后收集结果。
在这种情况下,我会这样做 ThreadEncipher
(您没有向我们展示其来源,所以我在做假设)采用一个参数,该参数用作数组指数。不是让 ThreadEncipher
从 inputString
读取并写入 outputString
,而是让它读取并写入数组的一个索引。这样,每个线程都可以同时读写。在生成所有这些线程之后,您可以等待所有这些线程完成,然后您可以处理输出数组,或者由于 array<String^>^
已经是您的 return 类型,只需 return 照原样。
其他想法:
- 您在这里混合了非托管和托管对象。如果你选择一个并坚持下去会更好。由于您使用的是 C++/CLI,我建议您坚持使用托管对象。我会停止使用
std::string
,而只使用System::String^
。 - 由于您的 CPU 有 4 个核心,您不会通过使用超过 4 个线程来获得任何加速。当 32 个线程花费的时间比 4 个长时,请不要感到惊讶,因为您正在执行 8 倍的字符串操作,并且您有 32 个线程争夺 4 个处理器内核。
您的字符串拆分代码比需要的更复杂。你那里有五个不同的案例,我必须坐下来考虑一下,以确保它是正确的。试试这个:
int totalLen = str2->length; for (int i = 0; i < nThreads; i++) { int startIndex = totalLen * i / nThreads; int endIndex = totalLen * (i+1) / nThreads; int substrLen = endIndex - startIndex; String^ substr = str2->SubString(startIndex, substrLen); ... }