避免Parallel.ForEach(C#Xamarin Android)期间ProgressDialog冻结
基于stackoverflow的主题和示例,我编写了一个“IP地址服务器搜索器”,试图通过http连接到192.168.x.1-192.168.x.254的所有可能的IP地址,以查找在特定端口上服务的前两台PC 它工作正常,对话框显示并更新1…254,只要:避免Parallel.ForEach(C#Xamarin Android)期间ProgressDialog冻结,c#,android,asynchronous,parallel-processing,progressdialog,C#,Android,Asynchronous,Parallel Processing,Progressdialog,基于stackoverflow的主题和示例,我编写了一个“IP地址服务器搜索器”,试图通过http连接到192.168.x.1-192.168.x.254的所有可能的IP地址,以查找在特定端口上服务的前两台PC 它工作正常,对话框显示并更新1…254,只要: -我将连接超时时间保持在并行循环内的2000ms(36sec),或 -我减少到200ms,但是在不使用并行的情况下一个接一个地(需要22秒)!:D) 但是如果我通过设置:.ConnectTimeout=200来加快进程;让它平行运行>> -
-我将连接超时时间保持在并行循环内的2000ms(36sec),或
-我减少到200ms,但是在不使用并行的情况下一个接一个地(需要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
btnSearchAddress。单击+=委托{
//…获取WifiManager的IP地址
_pzcid._myIPstring=Formatter.FormatIpAddress(i);
//在对话框栏中显示%
进程对话进程;
progress=newandroid.App.ProgressDialog(此对话框);
进度。可设置可取消(false);
_dialogCancelled=false;//静态bool…定义如下
progress.SetButton(-3,“停止”,(发送方,e)=>{//取消搜索
_dialogCancelled=true;
});
progress.Max=_MaxIP;//=254
SetIcon(Android.Resource.Drawable.IcMenuSearch);
progress.SetProgressStyle(ProgressDialogStyle.Horizontal);
progress.SetMessage(“已测试/找到IP地址…”);
progress.Show();
var task=task.Run(异步()=>{
wait Task.Yield();//强制从现在开始异步运行命令
_查找(edtPort.Text,edtDevicename.Text);
而(!\u对话框已取消){//
等待任务延迟(时间跨度从毫秒(100));
RunOnUiThread(()=>{
progress.progress=\u start.Value;
//progress.Notify();//将导致“未被线程锁定…”错误
});
};
等待任务;
if(progress.IsShowing)
进步。解散();
对于(int j=0;j<\u addresses.Count;j++){
_pzcid.AddLog2List(_地址[j]);
如果(j==0)RunOnUiThread(()=>edtBaseurl1.Text=_地址[0]);
如果(j==1)RunOnUiThread(()=>edtBaseurl2.Text=_地址[1]);
}
});
};//btnSearchAddress。单击
这是一个称为搜索循环的异步:
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()
const int_MaxIP=254;
公共静态bool\u dialogCancelled=false;
public static multi-threadvalues.ThreadSafeInt _start=新的多线程值。ThreadSafeInt();//有多少服务器响应
public static multi-threadvalues.ThreadSafeInt _found=新的多线程值。ThreadSafeInt();//有多少服务器响应
public static multi-threadvalues.ThreadSafeList _addresses=new multi-threadvalues.ThreadSafeList();//服务器的每个IP,谁响应
公共静态异步void _FIND(字符串端口,字符串名称){
等待任务;
_已启动。值=0;
_已找到。值=0;
_地址。清除();
字符串p=_pzcId._myIPstring;
如果(p==“”)返回;
常量字符_点=';
StringBuilder str192=新的StringBuilder(64);
Int16点=0;
对于(int c=0;c{
等待任务;
_start.Add1();
//int s=_start.Value;
//如果(s<_numberOfthreads)Thread.Sleep(500*s);//无用
布尔成功=假;
var host0=str192168+i;
字符串url_txt=WebCall.CreateTestURL(主机0、端口、名称);
URL myUrl=新URL(URL_txt);
试一试{
使用(HttpURLConnection urlc=(HttpURLConnection)myUrl.OpenConnection()){
urlc.RequestMethod=“GET”//或urlc.setRequestMethod(“HEAD”);
SetRequestProperty(“连接”、“关闭”);
urlc.ConnectTimeout=200;
等待urlc.ConnectAsync();
成功=(urlc.ResponseCode==HttpStatus.Ok);
}
}
捕获(例外情况除外){
//_地址。添加(“**错误:+url\u txt+”--“+ex.Message);
}
Dispose();
如果(成功){
_found.Add1();
_地址。添加(主机0);
如果(_found.Value==2){
StopMe.Stop();//找到2台主机>>退出for循环
}
}
如果(_dialogCancelled&&!StopMe.IsStopped)StopMe.Stop();//StopMe是ForEach状态
});//lambra ForEach
_dialogCancelled=true;//强制完成>>自动关闭ProcessDialog
}//void _FIND()
问:在CPU负载很重的情况下,如何强制更新(刷新)ProcessDialog?(如果还有什么我可以改进的,请与我分享!:)你说的强制升级是什么意思?@mjwills:对不起,mistypo.编辑为:[强制更新(刷新)]