根据stackoverflow上的主题和示例,我写了一个" IP地址服务器搜索器"尝试通过http连接到192.168.x.1 - 192.168.x.254的所有可能的IP地址,以找到在特定端口上服务的前2台PC。
它工作得很好,对话框显示和更新1 .... 254只要: - 我将连接超时保留在并行循环内的 2000ms ( 36秒),或者 - 我减少到 200ms ,但是在没有的情况下逐行使用Parallel(需要 22秒!:D)
但如果我通过设置加速进程:.ConnectTimeout = 200;并保持平行>>
- 对话框停止在0%
- 在 8秒之后,它发现了2个IP,
- 完成作业,对话框消失
(没有进程更新:()
以下是按钮的代码:
<!-- language: lang-cs -->
btnSearchAddress.Click += delegate {
// ... get IP address of the WifiManager
_PzzCID._myIPstring = Formatter.FormatIpAddress(i);
// SHOW % in a dialog bar
ProgressDialog progress;
progress = new Android.App.ProgressDialog( this );
progress.SetCancelable(false);
_dialogCancelled = false; // static bool ... defined below
progress.SetButton(-3, "STOP", (sender, e) => { // cancelling the search
_dialogCancelled = true;
});
progress.Max = _MaxIP; // =254
progress.SetIcon(Android.Resource.Drawable.IcMenuSearch);
progress.SetProgressStyle(ProgressDialogStyle.Horizontal);
progress.SetMessage("Tested / Found IP addresses...");
progress.Show();
var task = Task.Run( async () => {
await Task.Yield(); // force to run the commands from now on Async
_FIND( edtPort.Text, edtDevicename.Text );
while ( ! _dialogCancelled ) { //
await Task.Delay( TimeSpan.FromMilliseconds(100));
RunOnUiThread(() => {
progress.Progress = _started.Value;
//progress.Notify(); // would cause "not locked by thread ..." error
});
};
await Task.WhenAll();
if (progress.IsShowing)
progress.Dismiss();
for (int j = 0; j < _addresses.Count; j++) {
_PzzCID.AddLog2List(_addresses[j]);
if (j==0) RunOnUiThread(() => edtBaseurl1.Text = _addresses[0]);
if (j==1) RunOnUiThread(() => edtBaseurl2.Text = _addresses[1]);
}
});
}; // btnSearchAddress.Click
这是异步调用搜索循环:
const int _MaxIP = 254;
public static bool _dialogCancelled = false;
public static MultiThreadValues.ThreadSafeInt _started = new MultiThreadValues.ThreadSafeInt(); // how many servers responded
public static MultiThreadValues.ThreadSafeInt _found = new MultiThreadValues.ThreadSafeInt(); // how many servers responded
public static MultiThreadValues.ThreadSafeList<string> _addresses = new MultiThreadValues.ThreadSafeList<string>(); // each IP with server, who responded
public static async void _FIND( string port, string name ) {
await Task.Yield();
_started.Value = 0;
_found.Value = 0;
_addresses.Clear();
string p = _PzzCID._myIPstring;
if (p == "") return;
const Char _dot = '.';
StringBuilder str192 = new StringBuilder(64);
Int16 dots = 0;
for (int c = 0; c < p.Length; c++) {
if ( p[c] == _dot) dots++;
str192.Append(p[c]);
if (dots == 3) break; // found 3. "." = 192.168.1.
}
string str192168 = str192.ToString();
const Int16 _numberOfthreads = 8;
IEnumerable<int> _all_1_to_254 = Enumerable.Range (1, _MaxIP);
// Parallel.ForEach(GetRateLimitedResource,
Parallel.ForEach(_all_1_to_254, new ParallelOptions() { MaxDegreeOfParallelism = _numberOfthreads },
async (i, StopMe) => {
await Task.Yield();
_started.Add1();
//int s = _started.Value;
//if (s < _numberOfthreads) Thread.Sleep(500 * s); // useless
bool success = false;
var host0 = str192168 + i;
string url_txt = WebCall.CreateTestURL(host0, port, name) ;
URL myUrl = new URL (url_txt);
try {
using (HttpURLConnection urlc = (HttpURLConnection)myUrl.OpenConnection ()) {
urlc.RequestMethod = "GET"; //OR urlc.setRequestMethod ("HEAD");
urlc.SetRequestProperty("Connection", "close");
urlc.ConnectTimeout = 200;
await urlc.ConnectAsync();
success = (urlc.ResponseCode == HttpStatus.Ok);
}
}
catch (Exception ex) {
//_addresses.Add("**ERROR:"+url_txt+ " --- " + ex.Message);
}
myUrl.Dispose();
if (success) {
_found.Add1();
_addresses.Add(host0);
if (_found.Value == 2) {
StopMe.Stop(); // Found 2 hosts >> Exit from for-loop
}
}
if (_dialogCancelled && ! StopMe.IsStopped) StopMe.Stop(); // StopMe is a ForEach state
}); // lambra ForEach
_dialogCancelled = true; // force finish >> to dismiss the ProcessDialog automatically
} //void _FIND()
问:在CPU负载过重的情况下,如何强制更新(刷新)ProcessDialog? (如果还有其他我可以改进的地方,请与我分享!)