异步函数冻结UI线程



我有一个异步函数,当我执行它时,它仍然冻结/滞后于UI线程。这是我调用它的函数。

private void TcpListenerLogic(object sender, string e)
{
Application.Current.Dispatcher.BeginInvoke((Action)async delegate {
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
// Get properties for new anchor
string testInformation = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + results.test_id);
}                    
}
catch (Exception exception)
{
// Writing some Trace.WriteLine()'s
}
});

}

这是冻结我的UI线程的异步函数

public static async Task<string> getJsonFromURL(string url)
{

try
{
string returnString = null;
using (System.Net.WebClient client = new System.Net.WebClient())
{
returnString = await client.DownloadStringTaskAsync(url);
}
return returnString;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return null;
}
}

我已经尝试过让TcpListenerLogic中的所有内容都在新的Thread:中运行

new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
}).Start();

这导致整个UI完全冻结。我尝试使TcpListenerLogic异步并等待调度器,这也使一切永久冻结。我还尝试使TcpListenerLogic异步并离开调度器。调度器之所以在那里,是因为我通常在那里有一些UI代码,而这些代码是我在测试中遗漏的。

我曾在互联网上冒险过很多次,但没有BackgroundWorkerThreadPool或其他方法帮助我。如果有人能帮助我解决这个特殊的问题,或者有资源可以提高我对C#中异步函数的理解,我将不胜感激

编辑

根据要求,深入了解如何调用此事件处理程序。我有System.Net.Websocket,它连接到我正在使用的后端API,每次他收到新数据时都会触发事件。为了保证套接字在打开时能监听多久,有一个while循环来检查客户端状态:

public event EventHandler<string> TcpReceived;
public async void StartListener(string ip, int port, string path)
{
try
{
using (client = new ClientWebSocket())
{
try
{   // Connect to backend
Uri serverUri = new Uri("ws://" + ip + ":" + port.ToString() + path );
await client.ConnectAsync(serverUri, CancellationToken.None);
}
catch (Exception ex)
{
BackendSettings.IsConnected = false;
Debug.WriteLine("Error connecting TCP Socket: " + ex.ToString());
}
state = client.State;
// Grab packages send in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
try
{
// **Just formatting the received data until here and writing it into the "message" variable**//
TcpReceived(this, message);
// Close connection on command
if (result.MessageType == WebSocketMessageType.Close)
{
Debug.WriteLine("Closing TCP Socket.");
shouldstayclosed = true;
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
break;
}
state = client.State;
}
catch
{
BackendSettings.IsConnected = false;
state = client.State;
}
}
state = client.State;
}
}
catch (Exception ex)
{
// Some error messages and settings handling
}
}

事件附加了一个处理程序:

TcpReceived += TcpListener_TcpReceived;

这就是Handler,它调用前面看到的";TcpListenerLogic";。

private void TcpListener_TcpReceived(object sender, string e)
{
TcpListenerLogic(sender, e);
//App.Current.Dispatcher.BeginInvoke(new Action(() => {
//      TcpListenerLogic(sender, e);
//}));
//new Thread(() =>
//{
//    Thread.CurrentThread.IsBackground = true;
//    TcpListenerLogic(sender, e);
//}).Start();
}

我以前有";TcpListenerLogic";作为处理程序,但我想尝试不同的方法来调用它;TcpListenerLogic";已经看了。我所有的尝试都使用了所有提到的设置,遗憾的是一无所获。

非常感谢@TheodorZoulias帮助我找到问题的解决方案。

事实证明,这不是异步函数本身,而是它被调用的频率。它大约每秒被调用120次。我的解决方案首先通过一个新线程调用Listener方法:

new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
MainWindow.tcpListener.StartListener(ip, portNumber, "/api/");
}).Start();

为了限制每秒发生的调用数量,我添加了一个调度程序计时器,它在调用后重置bool,由我的Event执行。

readonly System.Windows.Threading.DispatcherTimer packageIntervallTimer = 
new System.Windows.Threading.DispatcherTimer();
bool readyForNewPackage = true;
private void ReadyForPackage(object sender, EventArgs e)
{
readyForNewPackage = true;
}
public async void StartListener(string ip, int port, string path)
{
packageIntervallTimer.Interval = TimeSpan.FromMilliseconds(50);
packageIntervallTimer.Tick += (s, e) => { Task.Run(() => ReadyForPackage(s, e)); };
packageIntervallTimer.Start();

然后,我将while循环中的所有内容都包装成一个基于bool的if条件,最重要的部分是让我的";事件事件处理程序TcpReceived";在那里:

// Grab packages sent in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
if (readyForNewPackage == true)
{
readyForNewPackage = false;
try
{
....
TcpReceived(this, message);
....
}
catch
{
...
}
}
}

我将TcpListenerLogic添加到Eventhandler:

TcpReceived += TcpListenerLogic;

我的TcpListenerLogic现在看起来是这样的(名称已经更改(:

private async void TcpListenerLogic(object sender, string e)
{
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
string testID = "";
if (results.test_id is JValue jValueTestId)
{
testID = jValueTestId.Value.ToString();
}
else if (results.test_id is string)
{
testID = results.test_id;
}
// Get properties for new object
string information = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + testID );
if (information != null)
{
await App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
// Create object out of the json string
TestStatus testStatus = new TestStatus();
testStatus.Deserialize(information);
if (CommunicationCommands.isNameAlreadyInCollection(testStatus.name) == false)
{
// Add new object to the list
CommunicationCommands.allFoundTests.Add(testStatus);
}
}));
{
}
catch (Exception exception)
{
....
}
}

添加一个新线程来执行任何步骤都会导致问题,所以请记住,所有这些都使用在开始时为"线程"创建的线程;StartListener">

最新更新