Asynchronous trap I/O

Source: Internet
Author: User
Tags getstream

Many tutorials and materials emphasize that a smooth user experience requires asynchronous assistance. The core idea is to ensure that the user's front-end interaction always has the highest priority, so that all time-consuming logic can be put in the background, when everything is complete, inform the front end of a prompt or continue the next step. With. NET development, the promotion of async and await keywords, the steady development of task parallel Library (TPL), and more attention and adoption of asynchronous programming. In many cases, it is very convenient to solve various performance problems, but it also brings many traps.

Here I am throwing out a trap encountered in a real project. First, Let's explain the background: spreadjs has an Excel I/O component, which is an ASP. net MVC web API (mvc4) is used to import an Excel file to spreadjs. The process is that the client uploads an Excel file first, and the server receives the file and reads the content, it is returned to the client in JSON format unique to spreadjs. After working normally for a long time, a "great god" customer reported that he would have a probability of random import failure during excel I/O, the specific manifestation is that an IO error is prompted in the returned JSON data. Okay, attach the code snippet of the user scenario (skipped the Script Reference, Dom, and other confidential code ):

$(document).ready(function() {  // initialize 10 spreadjs widgets  for(var i = 0; i < 10; i++) {    $("#ss_" + i).wijspread({ sheetCount: 2 });  }  // import handler  $("#importButton").click(function() {    for(var i = 0; i < 10; i++) {      importToSpread("ss" + i);    }  });  // import process  function importToSpread(target) {    var formData = new FormData();    formData.append("file", $("#importingExcelFile").get(0).files[0]);    formData.append("ExcelOpenFlags", "NoFlagsSet");    formData.append("TextFileOpenFlags", "None");    formData.append("Password", "");    $.ajax( {      url: "http://your.excelio.path/xsapi/import",      type: "POST",      success: function(data, textStatus, jqXHR) {        $("#" + target).wijspread("spread").fromJSON(JSON.parse(jqXHR.responseText).spread);      },      data: formData,      contentType: false,      processData: false,      headers: { "Accept": "application/json" }    });  }});

Maybe you may have something to say: Is this obviously difficult? Is there a real scenario where a file is repeatedly imported for 10 times? Well, this is a matter of social engineering.

Based on your code, you can analyze some key information:
1. the user quickly submitted multiple requests and uploaded files in a short time;
2. Random Io errors will occur in the returned results;
It can be concluded that when the server processes the uploaded Excel file, a file is unavailable under certain circumstances, leading to Io exceptions thrown by the processing program. What causes Io to be unavailable? As a developer, the easiest way to think of it is to sacrifice the IDE and directly mount the debugger, as long as this Io exception is caught. After several attempts, I/O exceptions are finally displayed, such:

650) This. width = 650; "width =" 560 "Height =" 175 "Title =" IO-exception "style =" border: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; Background-image: none; "alt =" IO-exception "src =" http://image.mamicode.com/info/201409/20181013001641951604.png "border =" 0 "/>

It seems that the previous analysis is correct. Files are unavailable in specific situations, but why? From the above Io exception information, we can see that this file is an uploaded file temporarily saved by ASP. NET. In ASP. NET Web APIs, the ideas and methods for processing uploaded files are as follows:

var root = HttpContext.Current.Server.MapPath("~/App_Data");var provider = new MultipartFormDataStreamProvider(root);try {  await Request.Content.ReadAsMultipartAsync(provider);} catch (Exception ex) {  return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);}var file = provider.FileData.FirstOrDefault();// File.OpenRead(file.LocalFileName) // may get exception here

From this segment, it is easy to analyze two possible causes of file IO:
1. The localfilename of the file is not unique.
2. The Asynchronous Operation for reading the uploaded content is completed but the file has not been released
Obviously, the first one can be ruled out, because the exception information shows that the file name has a guid, which can be absolutely unique. Therefore, the problem must occur in asynchronous processing.

To thoroughly understand what happened, I checked the source code of readasmultipartasync. Here, the getstream Method on multipartformdatastreamprovider is called to process uploaded files:

//... Omitted parameter processing string localfilename = This. getlocalfilename (headers); STR = path. combine (this. _ rootpath, path. getfilename (localfilename ));//... partial unrelated logic multipartfiledata item = new multipartfiledata (headers, STR); this. _ filedata. add (item); Return file. create (STR, this. _ buffersize, fileoptions. asynchronous );

Here, getlocalfilename is called to obtain the temporary file name. It is clear that GUID is used. newguid () to ensure that the file name will never be repeated. when the focus is switched to the last sentence, a writable filestream is returned. Note that the third parameter here is fileoptions. asynchronous, that is to say, this filestream is actually asynchronous Io, but the internal processing logic directly follows the subsequent logic without waiting for this result, in this way, Io exceptions may easily occur when the server runs at high Io concurrency.

The problem is analyzed above, but how can we solve it (a pm voice: Who is it? Hurry up, the customer is busy)? It's very easy. Just remove the asynchronous Io call. Okay, the code is not simple at all. Rewrite this getstream method to ensure that the obtained filestream is synchronized. Although the performance is reduced to a certain extent, it can solve the problem.

Refer to the sample project code:

Update supplement: In ASP. net MVC 5 re-writes the entire class where readasmultipartasync is located, and has fixed this problem (at least I tried 1000 times without pressure at the same time). Refer to the asynciotrap_v5 project in the example.

Note: wijmo 5 jquery UI component set wijmo was released on oschina yesterday, the largest update in five years, mobile first!. However, the wijmo 5 beta version released this time does not contain spreadjs.


This article from the "grape city control technical team blog" blog, please be sure to keep this source http://powertoolsteam.blog.51cto.com/2369428/1550437

Asynchronous trap I/O

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.