WinInet编程中如何使用异步

在WinInet编程中,同步的使用方法如下:

InternetOpen->InternetOpenUrl->HttpQueryInfo->InternetReadFile->InternetCloseHandle;在InternetOpenUrl和InternetReadFile时会导致程序阻塞,知道操作完成,同步的好处就是比较简单,调试方便。

异步的使用方法如下:

1)InternetOpen,需指定是异步;

2)InternetSetStatusCallback,设置回调;

3)InternetOpenUrl,需指定回调参数;

4)WaitForSingObject或WaitForMultipleObjects,接收信号量;

5)HttpQueryInfo;

6)InternetReadFileEx,需指定回调参数(CE或mobile下是InternetReadFileExA);

7)WaitForSingObject或WaitForMultipleObjects,接收信号量;

8)InternetSetStatusCallback,卸载回调;

9)InternetCloseHandle。

异步比同步要复杂了不少,重点在于回调函数。在回调中,系统会及时返回各种系统定义的HTTP消息,我们根据这些消息来设置某些信号量。在WaitForSingObject或WaitForMultipleObjects里,等待这些信号(当然也可以等待用户的取消动作)。当有正确的信号返回时,继续往下的操作。下面一个例子代码:上面的理论同样适用于wince或windows mobile平台

#include<windows.h>
#include<wininet.h>
#include<iostream.h>

DWORD dwNumKSent;
DWORD dwNumKToSend;
DWORD dwNumBytesComplete = 0;
char lpOutBuf[1024];
HANDLE hConnectedEvent, hRequestCompleteEvent;
HINTERNET hInstance, hConnect, hRequest;
char *lpszUrl, *lpszServer;

BOOL bAllDone = FALSE;

void __stdcall Callback(HINTERNET hInternet,
              DWORD dwContext,
              DWORD dwInternetStatus,
              LPVOID lpStatusInfo,
              DWORD dwStatusInfoLen);

void main(int argc, char *argv[])
{
    if (argc != 4)
    {
        cout << "Usage: sendreqexasync <server> <url> <size in kilobytes>" << endl;
        cout << "   Example: sendreqexasync www.foo.com /postfolder/upload.exe 256" << endl;
        return;
    }

    lpszServer = argv[1];
    lpszUrl = argv[2];
    dwNumKToSend = atoi(argv[3]);

    FillMemory(lpOutBuf, 1024, 'A');
    hConnectedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    hRequestCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    hInstance = InternetOpen("sendreqexasync",
                                       INTERNET_OPEN_TYPE_PRECONFIG,
                                       NULL,
                                       NULL,
                                       INTERNET_FLAG_ASYNC);

    if (hInstance == NULL)
    {
        cout << "InternetOpen failed, error " << GetLastError();
        return;
    }

    if (InternetSetStatusCallback(hInstance,
                                  (INTERNET_STATUS_CALLBACK)&Callback) == INTERNET_INVALID_STATUS_CALLBACK)
    {
        cout << "InternetSetStatusCallback failed, error " << GetLastError();
        return;
    }

    hConnect = InternetConnect(hInstance,
                               lpszServer,
                               INTERNET_DEFAULT_HTTP_PORT,
                               NULL,
                               NULL,
                               INTERNET_SERVICE_HTTP,
                               0,
                               1);
    if (hConnect == NULL)
    {
        if (GetLastError() != ERROR_IO_PENDING)
        {
            cout << "InternetConnect failed, error " << GetLastError();
            return;
        }
        WaitForSingleObject(hConnectedEvent, INFINITE);
    }

    hRequest = HttpOpenRequest(hConnect,
                               "POST",
                               lpszUrl,
                               NULL,
                               NULL,
                               NULL,
                               INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
                               2);
    if (hRequest == NULL)
    {
        if (GetLastError() != ERROR_IO_PENDING)
        {
            cout << "HttpOpenRequest failed, error " << GetLastError();
            return;
        }
        WaitForSingleObject(hRequestCompleteEvent, INFINITE);
    }

    INTERNET_BUFFERS IntBuff;

    FillMemory(&IntBuff, sizeof(IntBuff), 0);
    IntBuff.dwStructSize= sizeof(IntBuff);
    IntBuff.dwBufferTotal = 1024*dwNumKToSend;
    IntBuff.lpcszHeader = "Content-Type: text/text\r\n";
    IntBuff.dwHeadersLength = lstrlen(IntBuff.lpcszHeader);

    if (!HttpSendRequestEx(hRequest,
                           &IntBuff,
                           NULL,
                           0,
                           2))
    {
        if (GetLastError() != ERROR_IO_PENDING)
        {
            cout << "HttpSendRequestEx failed, error " << GetLastError();
            return;
        }
        cout << "HttpSendRequestEx called successfully" << endl;
        cout.flush();

        WaitForSingleObject(hRequestCompleteEvent, INFINITE);
    }

    for (dwNumKSent = 0; dwNumKSent < dwNumKToSend; dwNumKSent++)
    {
        DWORD dwBytesWritten;

        if(!InternetWriteFile(hRequest,
                               lpOutBuf,
                               1024,
                               &dwBytesWritten))
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
                cout << "InternetWriteFile failed, error " << GetLastError();
                return;
            }
            else
            {
                cout << "InternetWriteFile completing asynchronously" << endl;
                cout.flush();
                WaitForSingleObject(hRequestCompleteEvent, INFINITE);
            }
        }
    }

    cout << "Calling HttpEndRequest" << endl;
    cout.flush();
    if (!HttpEndRequest(hRequest, NULL, HSR_INITIATE, 2))
    {
        if (GetLastError() == ERROR_IO_PENDING)
        {
            cout << "HttpEndRequest called" << endl;
            cout.flush();
            WaitForSingleObject(hRequestCompleteEvent, INFINITE);
        }
        else
        {
            cout << "HttpEndRequest failed, error " << GetLastError() << endl;
            return;
        }
    }

    cout << "------------------- Read the response -------------------" << endl;
    char lpReadBuff[256];

    do
    {
        INTERNET_BUFFERS InetBuff;
        FillMemory(&InetBuff, sizeof(InetBuff), 0);
        InetBuff.dwStructSize = sizeof(InetBuff);
        InetBuff.lpvBuffer = lpReadBuff;
        InetBuff.dwBufferLength = sizeof(lpReadBuff) - 1;

        cout << "Calling InternetReadFileEx" << endl;
        cout.flush();

        if (!InternetReadFileEx(hRequest,
                              &InetBuff,
                              0, 2))
        {
            if (GetLastError() == ERROR_IO_PENDING)
            {
                cout << "Waiting for InternetReadFile to complete" << endl;
                cout.flush();
                WaitForSingleObject(hRequestCompleteEvent, INFINITE);
            }
            else
            {
                cout << "InternetReadFileEx failed, error " << GetLastError();
                cout.flush();
                return;
            }
        }

        lpReadBuff[InetBuff.dwBufferLength] = 0;
        cout << lpReadBuff;
        cout.flush();

        if (InetBuff.dwBufferLength == 0)
            bAllDone = TRUE;

    } while (bAllDone == FALSE);

    cout << endl << endl << "------------------- Request Complete ----------------" << endl;

}

void __stdcall Callback(HINTERNET hInternet,
              DWORD dwContext,
              DWORD dwInternetStatus,
              LPVOID lpStatusInfo,
              DWORD dwStatusInfoLen)
{
    cout << "Callback dwInternetStatus: " << dwInternetStatus << " Context: " << dwContext << endl;
    cout.flush();

    switch(dwContext)
    {
    case 1: // Connection handle
        if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED)
        {
            INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
            hConnect = (HINTERNET)pRes->dwResult;
            cout << "Connect handle created" << endl;
            cout.flush();
            SetEvent(hConnectedEvent);
        }
        break;
    case 2: // Request handle
        switch(dwInternetStatus)
        {
        case INTERNET_STATUS_HANDLE_CREATED:
            {
                INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
                hRequest = (HINTERNET)pRes->dwResult;
                cout << "Request handle created" << endl;
                cout.flush();
            }
            break;
        case INTERNET_STATUS_REQUEST_SENT:
            {
                DWORD *lpBytesSent = (DWORD*)lpStatusInfo;
                cout << "Bytes Sent: " << *lpBytesSent << endl;
                dwNumBytesComplete += *lpBytesSent;
            }
            break;
        case INTERNET_STATUS_REQUEST_COMPLETE:
            {
                INTERNET_ASYNC_RESULT *pAsyncRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
                cout << "Function call finished" << endl;
                cout << "dwResult: " << pAsyncRes->dwResult << endl;
                cout << "dwError:  " << pAsyncRes->dwError << endl;
                cout.flush();
                SetEvent(hRequestCompleteEvent);
            }
            break;
        case INTERNET_STATUS_RECEIVING_RESPONSE:
            cout << "Receiving Response" << endl;
            cout.flush();
            break;
        case INTERNET_STATUS_RESPONSE_RECEIVED:
            {
                DWORD *dwBytesReceived = (DWORD*)lpStatusInfo;
                cout << "Received " << *dwBytesReceived << endl;
                cout.flush();
            }

        }

    }

}

参考的异步类:

include <wininet.h>
#include <mmsystem.h>

class AsyncWinINet
{
public:
  typedef void (*notify_fp)(const StringMap&);

  class thread_info
  {
  public:
   thread_info(const String& _url,     //请求下载的地址(in)
    const StringMap& _request_headrs,   //请求头request_headrs(in)
    const notify_fp& _pfp,      //下载进度通知回调函数指针
    const StringMap& _pfp_param,
    String& _response_headrs,     //返回头response_headrs(out)
    const String& _saved_filename,    //下载内容保存文件名(in)
    String& _response_content,     //返回内容(out)
    size_t _read_content_size)     //控制保存在response_content中内容的长度(in)) :
    : request_headrs(_request_headrs), pfp(_pfp),
    pfp_param(_pfp_param),      //pfp函数传回参数
    response_headrs(_response_headrs), saved_filename(_saved_filename),
    response_content(_response_content), read_content_size(_read_content_size)
   {
    this->response_headrs.clear();
    this->response_content.clear();
    this->url = StringUtil::EncodeURIComponent(_url);
    for(int i = 0; i < 3; ++i)
    {
     this->hEvent[i] = CreateEvent(NULL,TRUE,FALSE,NULL);
    }
   }

   HANDLE hThread;
   DWORD dwThreadID;
   HANDLE hCallbackThread;
   DWORD dwCallbackThreadID;
   HANDLE hEvent[3];
   LPVOID hInternet;
   LPVOID hFile;
   DWORD dwStatusCode;
   DWORD dwContentLength;

   String url;         //请求下载的地址(in)
   const StringMap& request_headrs;   //请求头request_headrs(in)
   const notify_fp& pfp;      //下载进度通知回调函数指针
   const StringMap& pfp_param;     //pfp函数传回参数

   String& response_headrs;     //返回头response_headrs(out)
   const String& saved_filename;    //下载内容保存文件名(in)
   String& response_content;     //返回内容(out)
   size_t read_content_size;     //控制保存在response_content中内容的长度(in)
  };

  /*******************************************************************************
  * 函数:download
  * 功能:下载,返回WinINet_ERR_CODE值
  *   说明:关于notify_fp 类型说明: 函数的参数为StringMap类型,传回的变量名与变量值
  * 2007-12
  *******************************************************************************/
  static DWORD download(const String& url, //请求下载的地址(in)
   const StringMap& request_headrs,   //请求头request_headrs(in)
   const notify_fp& pfp,      //下载进度通知回调函数指针
   const StringMap& pfp_param,     //pfp函数传回参数
   String& response_headrs,     //返回头response_headrs(out)
   const String& saved_filename,    //下载内容保存文件名(in)
   String& response_content,     //返回内容(out)
   size_t read_content_size = 0);    //控制保存在response_content中内容的长度(in)

protected:
  static BOOL WaitExitEvent(thread_info *p);
  static DWORD WINAPI AsyncThread(LPVOID lpParameter);
  static DWORD WINAPI AsyncCallbackThread(LPVOID lpParameter);
  static VOID CALLBACK AsyncInternetCallback(HINTERNET hInternet,
   DWORD dwContext,
   DWORD dwInternetStatus,
   LPVOID lpvStatusInformation,
   DWORD dwStatusInformationLength);

};
#include "AsyncWinINet.h"

#include "stdafx.h"

#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "Wininet.lib")

DWORD AsyncWinINet::download(const Fagex::String &url, const Fagex::StringMap &request_headrs,
  const Fagex::AsyncWinINet::notify_fp &pfp, const Fagex::StringMap &pfp_param, Fagex::String &response_headrs,
  const Fagex::String &saved_filename, Fagex::String &response_content, size_t read_content_size)
{
  thread_info info(url, request_headrs, pfp,
   pfp_param, response_headrs, saved_filename,
   response_content, read_content_size);

  info.hThread = CreateThread(NULL,
   0,
   AsyncWinINet::AsyncThread,
   &info,
   NULL,
   &info.dwThreadID);

  WaitForSingleObject(info.hThread, INFINITE); //等待子线程安全退出
  CloseHandle(info.hThread);//关闭线程句柄

  return TRUE;
}

//---------------------------------------------------------------------
DWORD WINAPI AsyncWinINet::AsyncThread(LPVOID lpParameter)
{
  thread_info* p = (thread_info*)lpParameter;

  //a. 使用标记 INTERNET_FLAG_ASYNC 初始化 InternetOpen
  String user_agent("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler ; .NET CLR 2.0.50727)");
  StringMap iheadrs(p->request_headrs.begin(), p->request_headrs.end());
  StringMap::iterator it = iheadrs.find("User-Agent");
  if(it == iheadrs.end()) iheadrs["User-Agent"] = user_agent;
  else user_agent = it->second;

  p->hInternet = InternetOpen(user_agent.c_str(),
   INTERNET_OPEN_TYPE_PRECONFIG,
   NULL,
   NULL,
   INTERNET_FLAG_ASYNC);

  //ResetEvent(p->hEvent[0]);
  //p->hCallbackThread = CreateThread(NULL,
  // 0,
  // AsyncWinINet::AsyncCallbackThread,
  // p,
  // NULL,
  // &p->dwCallbackThreadID);
  //WaitForSingleObject(p->hEvent[0], INFINITE);//等待回调函数设置成功事件
  InternetSetStatusCallback(p->hInternet, AsyncWinINet::AsyncInternetCallback);

  String sheadrs;
  for(it = iheadrs.begin(); it != iheadrs.end(); ++it)
  {
   sheadrs += it->first + ":" + it->second;
   if(it->second.find(StringUtil::enter) == String::npos) { sheadrs += StringUtil::enter; }
  }
  sheadrs += StringUtil::enter;

  DWORD start_time = timeGetTime();
  ResetEvent(p->hEvent[0]); //重置句柄被创建事件
  p->hFile = InternetOpenUrl(p->hInternet, p->url.c_str(), sheadrs.c_str(), sheadrs.length(),
   INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, (DWORD)p);

  FILE *fp = fopen(p->saved_filename.c_str(), "w+");
  while(true)
  {
   if (NULL == p->hFile)
   {
    DWORD dwError = ::GetLastError();
    if (ERROR_IO_PENDING == dwError || ERROR_SUCCESS == dwError)
    {
     if (WaitExitEvent(p)) { break; }
    }
    else break;
   }

   //读取返回文件头
   DWORD dwLength = 0;
   LPVOID lpOutBuffer = NULL;
   while(true) //读取response_headrs数据
   {
    if(!HttpQueryInfo(p->hFile, HTTP_QUERY_RAW_HEADERS_CRLF,
       lpOutBuffer, &dwLength, NULL))
    {
     DWORD err_code = GetLastError();
     if (err_code == ERROR_HTTP_HEADER_NOT_FOUND) break;
     else if(err_code == ERROR_INSUFFICIENT_BUFFER)
     {
      lpOutBuffer = new char[dwLength];
      continue;
     }
     else break;
    }
    break;
   }
   if(lpOutBuffer != NULL)
   {
    p->response_headrs.append((char*)lpOutBuffer,dwLength);
    delete [] lpOutBuffer;
   }

   //e. 使用 HttpQueryInfo 分析头信息 HttpQueryInfo 使用非阻塞方式,所以不用等待
   DWORD dwStatusSize = sizeof(p->dwStatusCode);
   if (FALSE == HttpQueryInfo(p->hFile, //获取返回状态码
    HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
    &p->dwStatusCode, &dwStatusSize, NULL)) { break; }

   //判断状态码是不是 200
   if (HTTP_STATUS_OK != p->dwStatusCode) break;

   StringMap msgMap(p->pfp_param.begin(), p->pfp_param.end());
   msgMap["url"] = p->url;

   //获取返回的Content-Length
   //DWORD dwLengthSize = sizeof(p->dwContentLength);
   //if (FALSE == HttpQueryInfo(p->hFile,
   //HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
   //&p->dwContentLength, &dwLengthSize, NULL)) { p->dwContentLength = 0; }

   //f. 使用标记 IRF_ASYNC 读数据 InternetReadFileEx
   //为了向主线程报告进度,我们设置每次读数据最多 1024 字节

   char lpvBuffer[1024];
   p->dwContentLength = 0; //Content-Length: 202749
   while(true)
   {
    INTERNET_BUFFERS i_buf = {0};
    i_buf.dwStructSize = sizeof(INTERNET_BUFFERS);
    i_buf.lpvBuffer = lpvBuffer;
    i_buf.dwBufferLength = 1024;

    //重置读数据事件
    ResetEvent(p->hEvent[0]);
    if (FALSE == InternetReadFileEx(p->hFile, &i_buf, IRF_ASYNC, (DWORD)p))
    {
     if (ERROR_IO_PENDING == ::GetLastError())
     {
      if (WaitExitEvent(p)) break;
     }
     else break;
    }
    else
    {
     //在网络传输速度快,步长较小的情况下,InternetReadFileEx 经常会直接返回成功,
     //因此要判断是否发生了用户要求终止子线程事件。
     if (WAIT_OBJECT_0 == WaitForSingleObject(p->hEvent[2], 0))
     {
      ResetEvent(p->hEvent[2]);
      break;
     }
    }

    if(i_buf.dwBufferLength == 0)
    {
     DWORD time = timeGetTime() - start_time;
     if(time != 0)
     {
      Real speed = (Real)p->dwContentLength;
      speed /= ((Real)time)/1000.0f;
      speed /= 1024.0f;
      msgMap["speed"] = StringUtil::toString((DWORD)speed);
     }
     if(p->pfp) p->pfp(msgMap);
     break;
    }
    if(fp)
    {
     fwrite(i_buf.lpvBuffer, sizeof(char), i_buf.dwBufferLength, fp);
    }
    if(p->read_content_size > p->response_content.size())
    {
     p->response_content.append((char*)i_buf.lpvBuffer, i_buf.dwBufferLength);
    }
    p->dwContentLength += i_buf.dwBufferLength;
   }
   break;
  }

  if(fp)
  {
   fflush(fp); fclose(fp); fp = NULL;
  }

  if(p->hFile)
  {
   InternetCloseHandle(p->hFile);//关闭 m_hFile
   while (!WaitExitEvent(p)) //等待句柄被关闭事件或者要求子线程退出事件
   {
    ResetEvent(p->hEvent[0]);
   }
  }

  //设置子线程退出事件,通知回调线程退出
  SetEvent(p->hEvent[2]);

  //等待回调线程安全退出
  //WaitForSingleObject(p->hCallbackThread, INFINITE);
  //CloseHandle(p->hCallbackThread);

  //注销回调函数
  InternetSetStatusCallback(p->hInternet, NULL);
  InternetCloseHandle(p->hInternet);

  return TRUE;
}

//------------------------------------------------------------------------------------
DWORD WINAPI AsyncWinINet::AsyncCallbackThread(LPVOID lpParameter)
{
  thread_info *p = (thread_info*)lpParameter;
  InternetSetStatusCallback(p->hInternet, AsyncWinINet::AsyncInternetCallback);

  //通知子线程回调函数设置成功,子线程可以继续工作
  SetEvent(p->hEvent[0]);

  //等待用户终止事件或者子线程结束事件
  //子线程结束前需要设置子线程结束事件,并等待回调线程结束
  WaitForSingleObject(p->hEvent[2], INFINITE);

  return 0;
}

//----------------------------------------------------------------------------
VOID CALLBACK AsyncWinINet::AsyncInternetCallback(HINTERNET hInternet,
   DWORD dwContext,
   DWORD dwInternetStatus,
   LPVOID lpvStatusInformation,
   DWORD dwStatusInformationLength)
{
  thread_info* p = (thread_info*)dwContext;

  //在我们的应用中,我们只关心下面三个状态
  switch(dwInternetStatus)
  {
  //句柄被创建
  case INTERNET_STATUS_HANDLE_CREATED:
   p->hFile = (HINTERNET)(((LPINTERNET_ASYNC_RESULT)
    (lpvStatusInformation))->dwResult);
   break;

  //句柄被关闭
  case INTERNET_STATUS_HANDLE_CLOSING:
   SetEvent(p->hEvent[1]);
   break;

  //一个请求完成,比如一次句柄创建的请求,或者一次读数据的请求
  case INTERNET_STATUS_REQUEST_COMPLETE:
   if (ERROR_SUCCESS == ((LPINTERNET_ASYNC_RESULT)
    (lpvStatusInformation))->dwError)
   {
    //设置句柄被创建事件或者读数据成功完成事件
    SetEvent(p->hEvent[0]);
   }
   else
   {
    //如果发生错误,则设置子线程退出事件 这里也是一个陷阱,经常会忽视处理这个错误,
    SetEvent(p->hEvent[2]);
   }
   break;

  case INTERNET_STATUS_CONNECTION_CLOSED:
   SetEvent(p->hEvent[2]);
   break;

  }
}

//--------------------------------------------------------------------
BOOL AsyncWinINet::WaitExitEvent(thread_info *p)
{
  DWORD dwRet = WaitForMultipleObjects(3, p->hEvent, FALSE, INFINITE);

  switch (dwRet)
  {
  case WAIT_OBJECT_0://句柄被创建事件或者读数据请求成功完成事件
  case WAIT_OBJECT_0+1://句柄被关闭事件
  case WAIT_OBJECT_0+2://用户要求终止子线程事件或者发生错误事件
   break;
  }
  return WAIT_OBJECT_0 != dwRet;
}
 
时间: 2024-10-10 18:15:12

WinInet编程中如何使用异步的相关文章

网络编程中的同步与异步

网络编程中有三对关键的词,单线程与多线程.阻塞与非阻塞.同步与异步,同步与异步一直是比较疑惑的地方.以前认为,同步就是阻塞socket,异步就是非阻塞socket,现在发现这样理解很片面的,其实好多地方有同步异步的概念. 数字电路中的同步与异步是针对时钟来说的 同步时序逻辑电路:各触发器有相同的时钟脉冲,时钟脉冲到来时所有触发器状态同时改变异步时序逻辑电路:没有统一的时钟脉冲,所有触发器的状态转换不一定发生在同一时刻,某些触发器的状态转换有可能会延迟. 在通信原理中也有同步与异步的概念 同步传输

深入理解javascript编程中的同步和异步

JavaScript的优势之一是其如何处理异步代码.异步代码会被放入一个事件队列,等到所有其他代码执行后才进行,而不会阻塞线程.然而,对于初学者来说,书写异步代码可能会比较困难.而在这篇文章里,我将会消除你可能会有的任何困惑.理解异步代码 JavaScript最基础的异步函数是setTimeout和setInterval.setTimeout会在一定时间后执行给定的函数.它接受一个回调函数作为第一参数和一个毫秒时间作为第二参数.以下是用法举例: console.log( "a" );

你不知道的this—JS异步编程中的this

Javascript小学生都知道了javascript中的函数调用时会 隐性的接收两个附加的参数:this和arguments.参数this在javascript编程中占据中非常重要的地位,它的值取决于调用的模式.总的来说Javascript中函数一共有4中调用模式:方法调用模式.普通函数调用模式.构造器调用模式.apply/call调用模式.这些模式在如何初始化关键参数this上存在差异.“可能还有小伙伴不知道它们之间的区别,那我就勉为其难撸一撸吧!” 方法调用模式:函数是在某个明确的上下文对

Async/Await 异步编程中的最佳做法

近日来,涌现了许多关于 Microsoft .NET Framework 4.5 中新增了对 async 和 await 支持的信息. 本文旨在作为学习异步编程的“第二步”:我假设您已阅读过有关这一方面的至少一篇介绍性文章. 本文不提供任何新内容,Stack Overflow.MSDN 论坛和 async/await FAQ 这类在线资源提供了同样的建议. 本文只重点介绍一些淹没在文档海洋中的最佳做法. 本文中的最佳做法更大程度上是“指导原则”,而不是实际规则. 其中每个指导原则都有一些例外情况

异步编程中的最佳做法

原文链接 近日来,涌现了许多关于 Microsoft .NET Framework 4.5 中新增了对 async 和 await 支持的信息. 本文旨在作为学习异步编程的“第二步”:我假设您已阅读过有关这一方面的至少一篇介绍性文章. 本文不提供任何新内容,Stack Overflow.MSDN 论坛和 async/await FAQ 这类在线资源提供了同样的建议. 本文只重点介绍一些淹没在文档海洋中的最佳做法. 本文中的最佳做法更大程度上是“指导原则”,而不是实际规则. 其中每个指导原则都有一

异步编程中的最佳做法(Async/Await) --转

近日来,涌现了许多关于 Microsoft .NET Framework 4.5 中新增了对 async 和 await 支持的信息. 本文旨在作为学习异步编程的“第二步”:我假设您已阅读过有关这一方面的至少一篇介绍性文章. 本文不提供任何新内容,Stack Overflow.MSDN 论坛和 async/await FAQ 这类在线资源提供了同样的建议. 本文只重点介绍一些淹没在文档海洋中的最佳做法. 本文中的最佳做法更大程度上是“指导原则”,而不是实际规则. 其中每个指导原则都有一些例外情况

探究SynchronizationContext在.Net异步编程中的地位

原文:探究SynchronizationContext在.Net异步编程中的地位 引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要去学习,贴心的.NET提供Task线程包装类和await/async异步编程语法糖简化了异步编程方式. 相信很多开发者都看到如下异步编程实践原则:   实践原则  说明  例外情况  ①  避免 Async Void  最好使用 async Task 方法而不是 async void 方法  事件处理程序  ②  始终使用 await  不要混合阻塞式代码和

NET中的并行编程(TPL)——多线程、异步、任务和并行计算

https://masuit.com/1201 谈一谈.NET中的并行编程(TPL)——多线程.异步.任务和并行计算 懒得勤快 发表于2018-04-26 19:41:00 | 最后修改于2018-06-27 23:44:40 .NET 多线程 异步 高并发 分类:.NET开发技术 | 评论总数:0条 | 热度:2243℃ 我要编辑 写在前面: 在做了几个月的高并发项目的过程中,其实发现自己真的提升了不少,所以也想把这段时间的收获分享给大家,然后写这篇文章发现,写下来是一发不可收拾,所以这篇文章

Unix网络编程中的五种I/O模型_转

转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描述符.接受数据缓冲地址.大小传递给内核,但是如果此时 该与该套接口相应的缓冲区没有数据,这个时候就recvfrom就会卡(阻塞)在这里,知道数据到来的时候,再把数据拷贝到应用层,也就是传进来的地址空 间,如果没有数据到来,就会使该函数阻塞在那里,这就叫做阻塞I/O模型,如下图: 2. 非阻塞I/O模