TPL 和传统 .NET Framework 异步编程

.NET Framework 提供了以下两种标准模式,用于执行 I/O 密集型和计算密集型异步操作:

  • 异步编程模型 (APM),其中异步操作由一对 Begin/End 方法(如 FileStream.BeginRead 和Stream.EndRead)表示。

  • 基于事件的异步模式 (EAP),其中异步操作由 OperationName Async 和 OperationName Completed 方法/事件对(如 WebClient.DownloadStringAsync 和 WebClient.DownloadStringCompleted)表示。 (EAP 是在 .NET Framework 2.0 版本中引入的。)

任务并行库 (TPL) 可采用各种方法与任一异步模式协同使用。 可将 APM 和 EAP 操作作为任务向库使用者公开,也可以公开 APM 模式但用 Task 对象在内部实现它们。 在这两种情况下,可通过使用 Task 对象简化代码和利用以下有用的功能:

  • 在任务开始后随时以任务延续形式注册回调。

  • 通过使用 ContinueWhenAll 和 ContinueWhenAny 方法,或者 WaitAll 方法或 WaitAny 方法并列为响应 Begin_ 方法而执行的多个操作。

  • 封装同一 Task 对象中的异步 I/O 密集型和计算密集型操作。

  • 监视 Task 对象的状态。

  • 使用 TaskCompletionSource<TResult> 将操作状态封送处理至 Task 对象。

在任务中包装 APM 操作

System.Threading.Tasks.TaskFactory 和 System.Threading.Tasks.TaskFactory<TResult> 类都提供了几个 TaskFactory.FromAsync 和 TaskFactory<TResult>.FromAsync 方法的重载,可以将 APM Begin/End 方法对封装在 Task 或 Task<TResult> 实例中。 各种重载都可容纳任何具有零至三个输入参数的 Begin/End 方法对。

对于具有返回值(在 Visual Basic 中为 Function)的 End 方法的对,使用 TaskFactory<TResult> 中创建 Task<TResult> 的方法。 对于具有返回 void(在 Visual Basic 中为 Sub)的 End 方法,使用 TaskFactory 中创建 Task 的方法。

在极少情况下,如果 Begin 方法具有三个以上参数或包含 ref 或 out 参数,则提供仅封装 End 方法的其他 FromAsync 重载。

下面的示例显示了匹配 FileStream.BeginRead 和 FileStream.EndRead 方法的 FromAsync 重载的签名。 此重载采用三个输入参数,如下所示。

public Task<TResult> FromAsync<TArg1, TArg2, TArg3>(Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, //BeginReadFunc<IAsyncResult, TResult> endMethod, //EndReadTArg1 arg1, // the byte[] bufferTArg2 arg2, // the offset in arg1 at which to start writing dataTArg3 arg3, // the maximum number of bytes to readobject state // optional state information) 
Public Function FromAsync(Of TArg1, TArg2, TArg3)(ByVal beginMethod As Func(Of TArg1, TArg2, TArg3, AsyncCallback, Object, IAsyncResult),ByVal endMethod As Func(Of IAsyncResult, TResult),ByVal dataBuffer As TArg1,ByVal byteOffsetToStartAt As TArg2,ByVal maxBytesToRead As TArg3,ByVal stateInfo As Object)

第一个参数是匹配 FileStream.BeginRead 方法签名的 Func<T1,T2,T3,T4,T5,TResult> 委托。 第二个参数使用 IAsyncResult 并返回 TResult 的 Func<T,TResult> 委托。 由于 EndRead 返回一个整数,因此编译器会将 TResult 类型推断为 Int32 并将任务类型推断为 Task。 最后第四个参数与 FileStream.BeginRead 方法中的参数相同:

  • 存储文件数据的缓冲区。

  • 开始写入数据的缓冲区的偏移量。

  • 要从文件中读取的最大数据量。

  • 存储要传递至回调的用户定义状态数据的可选对象。

使用 ContinueWith 执行回调功能

如果需要访问文件中的数据,而不仅仅访问字节数,则 FromAsync 方法不能满足此操作。 请改用 Task,其 Result 属性包含文件数据。 可以通过向原始任务添加延续来实现这种操作。 延续执行通常由 AsyncCallback 委托执行的任务。 先前任务完成且填充了数据缓冲区后调用此操作。 (FileStream 对象应在返回前关闭。)

下面的示例演示如何返回封装 FileStream 类的 BeginRead/EndRead 对的 Task。

const int MAX_FILE_SIZE = 14000000;
public static Task<string> GetFileStringAsync(string path)
{FileInfo fi = new FileInfo(path);byte[] data = null;data = new byte[fi.Length];FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, data.Length, true);//Task<int> returns the number of bytes readTask<int> task = Task<int>.Factory.FromAsync(fs.BeginRead, fs.EndRead, data, 0, data.Length, null);// It is possible to do other work here while waiting// for the antecedent task to complete.// ...// Add the continuation, which returns a Task<string>. return task.ContinueWith((antecedent) =>{fs.Close();// Result = "number of bytes read" (if we need it.)if (antecedent.Result < 100){return "Data is too small to bother with.";}else{// If we did not receive the entire file, the end of the// data buffer will contain garbage.if (antecedent.Result < data.Length)Array.Resize(ref data, antecedent.Result);// Will be returned in the Result property of the Task<string>// at some future point after the asynchronous file I/O operation completes.return new UTF8Encoding().GetString(data);}});
}
Const MAX_FILE_SIZE As Integer = 14000000
Shared Function GetFileStringAsync(ByVal path As String) As Task(Of String)Dim fi As New FileInfo(path)Dim data(fi.Length) As ByteDim fs As FileStream = New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, data.Length, True)' Task(Of Integer) returns the number of bytes readDim myTask As Task(Of Integer) = Task(Of Integer).Factory.FromAsync(AddressOf fs.BeginRead, AddressOf fs.EndRead, data, 0, data.Length, Nothing)' It is possible to do other work here while waiting' for the antecedent task to complete.' ...' Add the continuation, which returns a Task<string>. Return myTask.ContinueWith(Function(antecedent)fs.Close()If (antecedent.Result < 100) ThenReturn "Data is too small to bother with."End If' If we did not receive the entire file, the end of the' data buffer will contain garbage.If (antecedent.Result < data.Length) ThenArray.Resize(data, antecedent.Result)End If' Will be returned in the Result property of the Task<string>' at some future point after the asynchronous file I/O operation completes.Return New UTF8Encoding().GetString(data)End Function)End Function

然后可调用此方法,如下所示。

Task<string> t = GetFileStringAsync(path);          // Do some other work:// ...try{Console.WriteLine(t.Result.Substring(0, 500));}catch (AggregateException ae){Console.WriteLine(ae.InnerException.Message);}            
Dim myTask As Task(Of String) = GetFileStringAsync(path)' Do some other work
' ...TryConsole.WriteLine(myTask.Result.Substring(0, 500))
Catch ex As AggregateExceptionConsole.WriteLine(ex.InnerException.Message)
End Try

提供自定义状态数据

在通常的 IAsyncResult 操作中,如果AsyncCallback 委托需要一些自定义状态数据,则必须通过 Begin 方法中的最后一个参数将它传入,以便可将数据打包到最终要传递至回调方法的 IAsyncResult 对象中。 当使用 FromAsync 方法时,通常无需此操作。 如果延续知道自定义数据,可直接在延续委托中捕获它。 下面的示例与以前的示例类似,但延续检查此延续的用户委托可直接访问的自定义状态数据,而不是检查历史任务的 Result 属性。

public Task<string> GetFileStringAsync2(string path)
{             FileInfo fi = new FileInfo(path);byte[] data = new byte[fi.Length];                       MyCustomState state = GetCustomState();FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, data.Length, true);// We still pass null for the last parameter because// the state variable is visible to the continuation delegate.Task<int> task = Task<int>.Factory.FromAsync(fs.BeginRead, fs.EndRead, data, 0, data.Length, null);return task.ContinueWith((antecedent) =>{// It is safe to close the filestream now.fs.Close();// Capture custom state data directly in the user delegate.// No need to pass it through the FromAsync method.if (state.StateData.Contains("New York, New York")){return "Start spreading the news!";}else{// If we did not receive the entire file, the end of the// data buffer will contain garbage.if (antecedent.Result < data.Length)Array.Resize(ref data, antecedent.Result);// Will be returned in the Result property of the Task<string>// at some future point after the asynchronous file I/O operation completes.return new UTF8Encoding().GetString(data);}});
}
Public Function GetFileStringAsync2(ByVal path As String) As Task(Of String)Dim fi = New FileInfo(path)Dim data(fi.Length) As ByteDim state As New MyCustomState()Dim fs As New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, data.Length, True)' We still pass null for the last parameter because' the state variable is visible to the continuation delegate.Dim myTask As Task(Of Integer) = Task(Of Integer).Factory.FromAsync(AddressOf fs.BeginRead, AddressOf fs.EndRead, data, 0, data.Length, Nothing)Return myTask.ContinueWith(Function(antecedent)fs.Close()' Capture custom state data directly in the user delegate.' No need to pass it through the FromAsync method.If (state.StateData.Contains("New York, New York")) ThenReturn "Start spreading the news!"End If' If we did not receive the entire file, the end of the' data buffer will contain garbage.If (antecedent.Result < data.Length) ThenArray.Resize(data, antecedent.Result)End If'/ Will be returned in the Result property of the Task<string>'/ at some future point after the asynchronous file I/O operation completes.Return New UTF8Encoding().GetString(data)End Function)End Function

同步多个 FromAsync 任务

当结合使用 FromAsync 方法时,静态 ContinueWhenAll 和 ContinueWhenAny 方法具有更大的灵活性。 下面的示例显示如何启动多个异步 I/O 操作,然后等待所有这些操作都完成后再执行延续。

public Task<string> GetMultiFileData(string[] filesToRead)
{FileStream fs;Task<string>[] tasks = new Task<string>[filesToRead.Length];byte[] fileData = null;for (int i = 0; i < filesToRead.Length; i++){fileData = new byte[0x1000];fs = new FileStream(filesToRead[i], FileMode.Open, FileAccess.Read, FileShare.Read, fileData.Length, true);// By adding the continuation here, the // Result of each task will be a string.tasks[i] = Task<int>.Factory.FromAsync(fs.BeginRead, fs.EndRead, fileData, 0, fileData.Length, null).ContinueWith((antecedent) =>{fs.Close();// If we did not receive the entire file, the end of the// data buffer will contain garbage.if (antecedent.Result < fileData.Length)Array.Resize(ref fileData, antecedent.Result);// Will be returned in the Result property of the Task<string>// at some future point after the asynchronous file I/O operation completes.return new UTF8Encoding().GetString(fileData);});}// Wait for all tasks to complete. return Task<string>.Factory.ContinueWhenAll(tasks, (data) =>{// Propagate all exceptions and mark all faulted tasks as observed.Task.WaitAll(data);// Combine the results from all tasks.StringBuilder sb = new StringBuilder();foreach (var t in data){sb.Append(t.Result);}// Final result to be returned eventually on the calling thread.return sb.ToString();});
}
Public Function GetMultiFileData(ByVal filesToRead As String()) As Task(Of String)Dim fs As FileStreamDim tasks(filesToRead.Length) As Task(Of String)Dim fileData() As Byte = NothingFor i As Integer = 0 To filesToRead.LengthfileData(&H1000) = New Byte()fs = New FileStream(filesToRead(i), FileMode.Open, FileAccess.Read, FileShare.Read, fileData.Length, True)' By adding the continuation here, the ' Result of each task will be a string.tasks(i) = Task(Of Integer).Factory.FromAsync(AddressOf fs.BeginRead,AddressOf fs.EndRead,fileData,0,fileData.Length,Nothing).ContinueWith(Function(antecedent)fs.Close()'If we did not receive the entire file, the end of the' data buffer will contain garbage.If (antecedent.Result < fileData.Length) ThenReDim Preserve fileData(antecedent.Result)End If'Will be returned in the Result property of the Task<string>' at some future point after the asynchronous file I/O operation completes.Return New UTF8Encoding().GetString(fileData)End Function)NextReturn Task(Of String).Factory.ContinueWhenAll(tasks, Function(data)' Propagate all exceptions and mark all faulted tasks as observed.Task.WaitAll(data)' Combine the results from all tasks.Dim sb As New StringBuilder()For Each t As Task(Of String) In datasb.Append(t.Result)Next' Final result to be returned eventually on the calling thread.Return sb.ToString()End Function)
End Function

仅用于 End 方法的 FromAsync 任务

在极少情况下,如果 Begin 方法需要三个以上的输入参数,或具有 ref 或 out 参数,可以使用仅表示 End 方法的 FromAsync 重载,例如,TaskFactory<TResult>.FromAsync(IAsyncResult, Func<IAsyncResult,TResult>)。 这些方法还可用于传递 IAsyncResult 并将其封装到 Task 的任何方案中。

static Task<String> ReturnTaskFromAsyncResult()
{IAsyncResult ar = DoSomethingAsynchronously();Task<String> t = Task<string>.Factory.FromAsync(ar, _ =>{return (string)ar.AsyncState;});return t;
}
Shared Function ReturnTaskFromAsyncResult() As Task(Of String)Dim ar As IAsyncResult = DoSomethingAsynchronously()Dim t As Task(Of String) = Task(Of String).Factory.FromAsync(ar, Function(res) CStr(res.AsyncState))Return t
End Function

启动和取消 FromAsync 任务

FromAsync 方法返回的任务具有 WaitingForActivation 状态,并在创建任务后在某个时刻由操作系统启动。 如果尝试调用此类任务上的“启动”,将引发异常。

无法取消 FromAsync 任务,因为基础 .NET Framework API 目前不支持取消正在进行中的文件或网络 I/O。 可以将取消功能添加到封装 FromAsync 调用的方法中,但只能在调用 FromAsync 之前或在调用完成之后响应取消(例如,在延续任务中)。

一些支持 EAP 的类(如 WebClient)不支持取消,但可以通过使用取消标记集成该本机取消功能。

将复杂的 EAP 操作公开为任务

TPL 不提供任何专用于以 FromAsync 系列方法包装 IAsyncResult 模式相同的方式封装基于事件的异步操作的方法。 但是,TPL 会提供 System.Threading.Tasks.TaskCompletionSource<TResult> 类,此类可用于将任意一组操作表示为 Task<TResult>。 这些操作可能同步、可能异步,可能是 I/O 密集型、也可能是计算密集型,还可能两者都是。

下面的示例显示如何使用 TaskCompletionSource<TResult> 将一组异步 WebClient 操作作为基础 Task<TResult> 向客户端代码公开。此方法允许输入 Web URL 数组和术语或名称来进行搜索,然后返回每个站点搜索字词出现的次数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;public class SimpleWebExample
{public Task<string[]> GetWordCountsSimplified(string[] urls, string name,CancellationToken token){TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>();WebClient[] webClients = new WebClient[urls.Length];object m_lock = new object();int count = 0;List<string> results = new List<string>();// If the user cancels the CancellationToken, then we can use the// WebClient's ability to cancel its own async operations.token.Register(() =>{foreach (var wc in webClients){if (wc != null)wc.CancelAsync();}});for (int i = 0; i < urls.Length; i++){webClients[i] = new WebClient();#region callback// Specify the callback for the DownloadStringCompleted// event that will be raised by this WebClient instance.webClients[i].DownloadStringCompleted += (obj, args) =>{// Argument validation and exception handling omitted for brevity.// Split the string into an array of words,// then count the number of elements that match// the search term.string[] words = args.Result.Split(' ');string NAME = name.ToUpper();int nameCount = (from word in words.AsParallel()where word.ToUpper().Contains(NAME)select word).Count();// Associate the results with the url, and add new string to the array that// the underlying Task object will return in its Result property.lock (m_lock){results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, name));// If this is the last async operation to complete,// then set the Result property on the underlying Task.count++;if (count == urls.Length){tcs.TrySetResult(results.ToArray());}}};#endregion// Call DownloadStringAsync for each URL.Uri address = null;address = new Uri(urls[i]);webClients[i].DownloadStringAsync(address, address);} // end for// Return the underlying Task. The client code// waits on the Result property, and handles exceptions// in the try-catch block there.return tcs.Task;}
}
Imports System.Collections.Generic
Imports System.Net
Imports System.Threading
Imports System.Threading.TasksPublic Class SimpleWebExampleDim tcs As New TaskCompletionSource(Of String())Dim token As CancellationTokenDim results As New List(Of String)Dim m_lock As New Object()Dim count As IntegerDim addresses() As StringDim nameToSearch As StringPublic Function GetWordCountsSimplified(ByVal urls() As String, ByVal str As String,ByVal token As CancellationToken) As Task(Of String())addresses = urlsnameToSearch = strDim webClients(urls.Length - 1) As WebClient' If the user cancels the CancellationToken, then we can use the' WebClient's ability to cancel its own async operations.token.Register(Sub()For Each wc As WebClient In webClientsIf wc IsNot Nothing Thenwc.CancelAsync()End IfNextEnd Sub)For i As Integer = 0 To urls.Length - 1webClients(i) = New WebClient()' Specify the callback for the DownloadStringCompleted' event that will be raised by this WebClient instance.AddHandler webClients(i).DownloadStringCompleted, AddressOf WebEventHandlerDim address As New Uri(urls(i))' Pass the address, and also use it for the userToken' to identify the page when the delegate is invoked.webClients(i).DownloadStringAsync(address, address)Next' Return the underlying Task. The client code' waits on the Result property, and handles exceptions' in the try-catch block there.Return tcs.TaskEnd FunctionPublic Sub WebEventHandler(ByVal sender As Object, ByVal args As DownloadStringCompletedEventArgs)If args.Cancelled = True Thentcs.TrySetCanceled()ReturnElseIf args.Error IsNot Nothing Thentcs.TrySetException(args.Error)ReturnElse' Split the string into an array of words,' then count the number of elements that match' the search term.Dim words() As String = args.Result.Split(" "c)Dim name As String = nameToSearch.ToUpper()Dim nameCount = (From word In words.AsParallel()Where word.ToUpper().Contains(name)Select word).Count()' Associate the results with the url, and add new string to the array that' the underlying Task object will return in its Result property.SyncLock (m_lock)results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, nameToSearch))count = count + 1If (count = addresses.Length) Thentcs.TrySetResult(results.ToArray())End IfEnd SyncLockEnd IfEnd Sub
End Class

有关包括其他异常处理且展示了如何通过客户端代码调用方法的更完整示例,请参阅如何:在任务中包装 EAP 模式。

请记住,通过 TaskCompletionSource<TResult> 创建的任何任务均由 TaskCompletionSource 启动,因此用户代码不应在此任务中调用 Start 方法。

使用任务实现 APM 模式

在某些情况下,可能需要通过使用 API 中 Begin/End 方法对直接公开 IAsyncResult 模式。 例如,可能想要与现有的 API 保持一致,或者可能具有需要这种模式的自动化工具。 在这种情况下,可使用任务来简化在内部实现 APM 模式的方式。

下面的示例显示如何使用任务实现长时间运行计算密集型方法的 APM Begin/End 方法对。

class Calculator
{public IAsyncResult BeginCalculate(int decimalPlaces, AsyncCallback ac, object state){Console.WriteLine("Calling BeginCalculate on thread {0}", Thread.CurrentThread.ManagedThreadId);Task<string> f = Task<string>.Factory.StartNew(_ => Compute(decimalPlaces), state);if (ac != null) f.ContinueWith((res) => ac(f));return f;}public string Compute(int numPlaces){Console.WriteLine("Calling compute on thread {0}", Thread.CurrentThread.ManagedThreadId);// Simulating some heavy work.Thread.SpinWait(500000000);// Actual implemenation left as exercise for the reader.// Several examples are available on the Web.return "3.14159265358979323846264338327950288";}public string EndCalculate(IAsyncResult ar){Console.WriteLine("Calling EndCalculate on thread {0}", Thread.CurrentThread.ManagedThreadId);return ((Task<string>)ar).Result;}
}public class CalculatorClient
{static int decimalPlaces = 12;public static void Main(){Calculator calc = new Calculator();int places = 35;AsyncCallback callBack = new AsyncCallback(PrintResult);IAsyncResult ar = calc.BeginCalculate(places, callBack, calc);// Do some work on this thread while the calulator is busy.Console.WriteLine("Working...");Thread.SpinWait(500000);Console.ReadLine();}public static void PrintResult(IAsyncResult result){Calculator c = (Calculator)result.AsyncState;string piString = c.EndCalculate(result);Console.WriteLine("Calling PrintResult on thread {0}; result = {1}",Thread.CurrentThread.ManagedThreadId, piString);}
}
Class CalculatorPublic Function BeginCalculate(ByVal decimalPlaces As Integer, ByVal ac As AsyncCallback, ByVal state As Object) As IAsyncResultConsole.WriteLine("Calling BeginCalculate on thread {0}", Thread.CurrentThread.ManagedThreadId)Dim myTask = Task(Of String).Factory.StartNew(Function(obj) Compute(decimalPlaces), state)myTask.ContinueWith(Sub(antedecent) ac(myTask))End FunctionPrivate Function Compute(ByVal decimalPlaces As Integer)Console.WriteLine("Calling compute on thread {0}", Thread.CurrentThread.ManagedThreadId)' Simulating some heavy work.Thread.SpinWait(500000000)' Actual implemenation left as exercise for the reader.' Several examples are available on the Web.Return "3.14159265358979323846264338327950288"End FunctionPublic Function EndCalculate(ByVal ar As IAsyncResult) As StringConsole.WriteLine("Calling EndCalculate on thread {0}", Thread.CurrentThread.ManagedThreadId)Return CType(ar, Task(Of String)).ResultEnd Function
End ClassClass CalculatorClientShared decimalPlaces As IntegerShared Sub Main()Dim calc As New CalculatorDim places As Integer = 35Dim callback As New AsyncCallback(AddressOf PrintResult)Dim ar As IAsyncResult = calc.BeginCalculate(places, callback, calc)' Do some work on this thread while the calulator is busy.Console.WriteLine("Working...")Thread.SpinWait(500000)Console.ReadLine()End SubPublic Shared Sub PrintResult(ByVal result As IAsyncResult)Dim c As Calculator = CType(result.AsyncState, Calculator)Dim piString As String = c.EndCalculate(result)Console.WriteLine("Calling PrintResult on thread {0}; result = {1}",Thread.CurrentThread.ManagedThreadId, piString)End SubEnd Class

使用 StreamExtensions 示例代码

在使用 .NET Framework 4 的并行编程示例中,Streamextensions.cs 文件包含多个引用实现,以将 Task 对象用于异步文件和网络 I/O。

请参阅

  • 任务并行库 (TPL)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438431.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hypixel服务器免费低延迟ip,国服hypixel服务器ip

[详情]The size of the downloaded application is huge, but its worth it. Sudoku puzzles free has a grand collection of free photo puzzles of various categories, for example, sports cars, houses, nature and others.Puzzle pieces is a constantly updated unique…

“菜”鸟理解.NET Framework(CLI,CLS,CTS,CLR,FCL,BCL)

既然要学.NET&#xff0c;就要先认识认识她&#xff0c;我不喜欢大段大段文字的东西&#xff0c;自己通过理解&#xff0c;画个图&#xff0c;来看看.NET的沉鱼落雁&#xff0c;闭月羞花之容。 最下层蓝色部分是.NET Framework的基础&#xff0c;也是所有应用软件的基础。.NET …

QQ炫舞手游显示进入服务器失败6,qq炫舞手游进不去怎么办 游戏进不去方法详解[多图]...

qq炫舞手游是新出的游戏&#xff0c;在近期非常的火爆&#xff0c;不过有不少的玩家都有进不了游戏的情况&#xff0c;下面安族小编给大家介绍一下游戏进不去方法详解。qq炫舞手游玩不了解决方法1.第一种方式就是内测还没有开启咯&#xff0c;所以玩家一般都是下载不到包的&…

那些年我们一起追逐的多线程(Thread、ThreadPool、委托异步调用、Task/TaskFactory、Parallerl、async和await)

一. 背景 在刚接触开发的头几年里&#xff0c;说实话&#xff0c;根本不考虑多线程的这个问题&#xff0c;貌似那时候脑子里也有没有多线程的这个概念&#xff0c;所有的业务都是一个线程来处理&#xff0c;不考虑性能问题&#xff0c;当然也没有考虑多线程操作一条记录存在的并…

ajax json 403,解决 Ajax 发送 post 请求出现 403 Forbidden 的三种方式

众所周知前端向后台发送 post 请求时&#xff0c;必须验证 csrf&#xff0c;否则会报错 403 Forbidden。使用 Django Form 表单可以直接在表单里面添加 {% csrf_token %} 即可&#xff0c;要是通过 Ajax 发送请求又该怎么办&#xff1f;下面提供三种解决办法&#xff1a;123Aja…

asp.net mvc webform和razor的page基类区别

接触过asp.net mvc的都知道&#xff0c;在传统的webform的模式下&#xff0c;page页面的基类是这样声明的&#xff1a; <% Page Language"C#" MasterPageFile"~/Views/Shared/Site.Master" Inherits"ViewPage" %> 如果是partial view的话…

frameset ajax,js控制frameSet示例

js控制frameSet示例1&#xff1a;js修改frameset的cols属性来达到修改各个页面所占的宽高&#xff0c;例如隐藏当前frame页。复制代码 代码如下:window.parent.document.getElementsByTagName("frameset")[0].cols"0,*";2&#xff1a;js调用其他frame页面的…

人生的抉择—aspx、ashx、asmx文件处理请求效率比较

总结&#xff1a; ashx&#xff1a;只是实现IHttpHandler接口 aspx&#xff1a;public class Page : TemplateControl, IHttpHandler 而TemplateControl是&#xff1a; abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService 所以aspx是重型…

ajax jsp模糊查询源码,Ajax动态执行模糊查询功能

Ajax动态执行模糊查询功能 内容精选换一换Profiling采集的数据较多&#xff0c;同时解析后展示的性能指标项也比较多&#xff0c;为方便用户快捷查找到具体性能指标的含义&#xff0c;提供命令行查询功能&#xff1a;不包含metric_name参数时&#xff0c;打印hiprof.sh脚本帮助…

一般处理程序(ashx)和页面处理程序(aspx)的区别

客官请看图 图中的Httphandler就是处理程序。 两者的共同点 如果把aspx处理程序和ashx处理程序放到上图中&#xff0c;他们是处在相同的位置的&#xff0c; 他们都实现了IHttphandler接口。实现了IHttphandler才具备处理请求的能力 两者的不同点 微软对aspx下足了功夫&#…

怎么在微云服务器找一个文件,微云文件在哪里打开_怎么快速找到微云文件

微云文件在哪里打开&#xff0c;这个问题困扰了许多的朋友&#xff0c;今天小编带着教程走向大家&#xff0c;我们可以使用微云可以快速连接和预览在线文档&#xff1b;同时加载和卸载多终端、手机、计算机、同步PAD数据传输&#xff0c;无需数据线。对于微云客户端&#xff0c…

ASP.NET Core真实管道详解[1]

ASP.NET Core管道虽然在结构组成上显得非常简单&#xff0c;但是在具体实现上却涉及到太多的对象&#xff0c;所以我们在 《ASP.NET Core管道深度剖析[共4篇]》 中围绕着一个经过极度简化的模拟管道讲述了真实管道构建的方式以及处理HTTP请求的流程。在这个系列 中&#xff0c;…

Wayland 显示服务器,wayland 1.8.0 发布,显示服务器

Wayland 1.8.0 发布&#xff0c;该版本现已提供下载&#xff1a; wayland-1.8.0.tar.xz&#xff1a;该版本与 RC2 相比的变化&#xff1a;publish-doc: Add script for publishing docs to the websiteconfigure.ac: bump to version 1.8.0 for the official releasescanner: d…

华为把服务器虚拟底层锁了,华为全面关闭解码锁服务:马上升级到很吓人的技术!...

原标题&#xff1a;华为全面关闭解码锁服务&#xff1a;马上升级到很吓人的技术&#xff01;华为余承东被网友称之为余大嘴&#xff0c;华为P20 Pro发布之后&#xff0c;余大嘴豪言华为P20的销量将超过2000万部&#xff0c;很就会推出一项“很吓人的技术”&#xff0c;没想到仅…

ASP.NET Core真实管道详解[2]:Server是如何完成针对请求的监听、接收与响应的【上】

Server是ASP .NET Core管道的第一个节点&#xff0c;负责完整请求的监听和接收&#xff0c;最终对请求的响应同样也由它完成。Server是我们对所有实现了IServer接口的所有类型以及对应对象的统称&#xff0c;如下面的代码片段所示&#xff0c;这个接口具有一个只读属性Features…

pos机未能连接服务器,pos 机链接不了服务器

pos 机链接不了服务器 内容精选换一换在本章节中&#xff0c;您将运行已部署好的游戏&#xff0c;登录游戏客户端。已准备好Windows机器&#xff0c;硬盘至少20G&#xff0c;且必须安装有显卡。服务器地址&#xff1a;节点的弹性IP地址&#xff0c;请登录CCE控制台&#xff0c;…

ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求

之所以称ASP.NET Core是一个Web开发平台&#xff0c;源于它具有一个极具扩展性的请求处理管道&#xff0c;我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求。ASP. NET Core应用的很多特性&#xff0c;比如路由、认证、会话、缓存等&#xff0c;也同时定制消息处理管…

emui消息推送服务器,别再抱怨,这次或许真的轮到你了,EMUI9.1推送进度再次更新...

最近几年里&#xff0c;华为在系统方面下的功夫可谓是大家有目共睹的。以往大家在使用华为EMUI操作系统的时候&#xff0c;或许会感觉到卡顿、应用启动时间过长、运行不流畅以及UI界面毫无亮点可言等&#xff0c;但那已经是过去的EMUI系统了&#xff0c;今日的EMUI系统已与往日…

ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

从《ASP.NET Core管道深度剖析&#xff08;1&#xff09;&#xff1a;采用管道处理HTTP请求》我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成&#xff0c;所以从总体设计来讲是非常简单的&#xff0c;但是就具体的实现来说&#xff0c;由于其中涉及很多对…

ASP.NET Core管道深度剖析(3):管道是如何处理HTTP请求的?

我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成&#xff0c;所以从总体设计来讲是非常简单的&#xff0c;但是就具体的实现来说&#xff0c;由于其中涉及很多对象的交互&#xff0c;我想很少人能够地把它弄清楚。为了让读者朋友们能够更加容易地理解管道…