user-0 提问: C调用Python一个运行时间长的函数，如何实时获取中间结果

回复:
user: user-0
content: 引用 5 楼 CharlesSimonyi 的回复:python代码中的download函数又是如何显示进度的？ 你的整个下载过程都写到一个函数里了，要调用完毕这个函数才获得结果，而且函数调用完毕的时候整个文件都下载完毕了。 先不说C如何调用的问题，你先解决这样的一个问题： 假如你的这个download函数拿给别人用，别人用python来调用你的download函数，如何实时获取进度并print()输出到屏幕上？ （注意，你写好代码拿给别人用，别人只能调用你写的代码，不能修改你的代码，就像标准库中的那些东西一样，你一般都只是调用，不会去修改它的代码） 所以这其实是个接口设计问题。 一个函数的调用需要很长时间才能完成，如何让调用者获取执行过程的进度，此类问题有多种解决方案： 1.拆分download函数，分步骤实现文件的下载，比如可以拆分成几个函数 打开连接（） 获取文件大小() 读一部分（size） 关闭连接（） 这样别人调用的时候，可以在一个循环中反复调用   读一部分（）并通过参数指定要读多少，这样调用者可以很好的知道进度。 Winhttp/Wininet等HTTP库在下载文件的时候都采用此办法 2.回调 download应提供一个参数以接收调用者提供的函数指针（或函数对象），download在下载过程中，每下载%5就调用一下这个回调函数通知调用者，这样调用者可以在回调函数中显示进度。 urllib使用的就是这种方式。 3.其它方法，如使用windows消息、事件来通知调用者，具有平台依赖性，用得较少   谢大神，一语惊醒梦中人啊。你的第一个方案非常不错。 第二个方案本来今天想研究一下的，想想太复杂的，就不干了 第三个是不适应的，有平台依赖性。  3Q Very Much！

user: user-1
content: 显示进度这种事情不要放在download函数里，你的接口要设计成，当别人调用你的download函数的时候，别人能获取到进度

user: user-1
content: python代码中的download函数又是如何显示进度的？ 你的整个下载过程都写到一个函数里了，要调用完毕这个函数才获得结果，而且函数调用完毕的时候整个文件都下载完毕了。 先不说C如何调用的问题，你先解决这样的一个问题： 假如你的这个download函数拿给别人用，别人用python来调用你的download函数，如何实时获取进度并print()输出到屏幕上？ （注意，你写好代码拿给别人用，别人只能调用你写的代码，不能修改你的代码，就像标准库中的那些东西一样，你一般都只是调用，不会去修改它的代码） 所以这其实是个接口设计问题。 一个函数的调用需要很长时间才能完成，如何让调用者获取执行过程的进度，此类问题有多种解决方案： 1.拆分download函数，分步骤实现文件的下载，比如可以拆分成几个函数 打开连接（） 获取文件大小() 读一部分（size） 关闭连接（） 这样别人调用的时候，可以在一个循环中反复调用   读一部分（）并通过参数指定要读多少，这样调用者可以很好的知道进度。 Winhttp/Wininet等HTTP库在下载文件的时候都采用此办法 2.回调 download应提供一个参数以接收调用者提供的函数指针（或函数对象），download在下载过程中，每下载%5就调用一下这个回调函数通知调用者，这样调用者可以在回调函数中显示进度。 urllib使用的就是这种方式。 3.其它方法，如使用windows消息、事件来通知调用者，具有平台依赖性，用得较少

user: user-0
content: 引用 2 楼 CharlesSimonyi 的回复:你的python代码是如何反馈进度的？ 是用print("10%")之类的方法输出的进度吗？ 还是用其他方式。 C代码是如何调用python的， 是通过Python/C API调用 还是把一个py文件当做可执行文件直接用ShellExecute之类的API去执行   def download(ftp_ip, ftp_port, ftp_user, ftp_pwd, remote_file, local_file): 	conn_result = _get_remote_file_size(ftp_ip, ftp_port, ftp_user, ftp_pwd, remote_file) 	ftps = conn_result[2] 	# start to download 	local_file_size = 0L 	try: 		download_result = False 		download_size = 0L 		ftps.voidcmd("TYPE I") 		download_connection = ftps.transfercmd('RETR ' + remote_file, local_file_size) 		percent = 0 		count = 0 		_progress(CLI_PROCESS_MAX_PRINT_LEN, percent) 		 		# 打开本地文件，准备从远端获取并下载 		with open(local_file, "ab") as local_save_file: 			while True: 				rcv_buffer = download_connection.recv(1024*1024*1024) 				write_len = local_save_file.write(rcv_buffer) 				。。。 				download_size += len(rcv_buffer) 				percent = int(float(download_size) / remote_file_size * 100) 				count = (count + 1) % 40 #(延迟打印规则) 				if 0 == count: 					# 打印进度条，后续删除_progress(CLI_PROCESS_MAX_PRINT_LEN, percent) 				if 100 == percent: 					# 打印进度条，后续删除 _progress(CLI_PROCESS_MAX_PRINT_LEN, percent) 	except Exception, e: 		# print "download fail with [%s]" % e 		download_result = UPG_FTP_DOWNLOAD_FAIL  	# 清理环境 	。。。 	return download_result    这个事是Python的下载组件，有部分是抽出来的方法，没有把代码贴出来。

user: user-0
content: 引用 2 楼 CharlesSimonyi 的回复:你的python代码是如何反馈进度的？ 是用print("10%")之类的方法输出的进度吗？ 还是用其他方式。 C代码是如何调用python的， 是通过Python/C API调用 还是把一个py文件当做可执行文件直接用ShellExecute之类的API去执行  int pgPycFtpsFileDownload( const IN  UPGRADE_FTP_INFO * pFtpInfo,                            const IN char * pcRemotePath,                            const IN char * pcLocalPath,                            const IN int ulMaxFileSize) {     int  ulRet       = 0;     PyObject * pModule    = NULL;     PyObject * pDict      = NULL;     PyObject * pFunction  = NULL;     PyObject * pArgus     = NULL;     PyObject * pResult    = NULL;           do     {          Py_Initialize();          (VOS_VOID)PyRun_SimpleString("import sys"); 		         if(NULL == pModule)         {             //xxxxxx记录错误             break;         }          pDict      = PyModule_GetDict(pModule);         pFunction  = PyDict_GetItemString(pDict, "download");                  if(NULL == pFunction)         {             //xxxxxx记录错误             break;         }          pArgus = Py_BuildValue( "(s, i, s, s, s, s, l)",                             pFtpInfo->ucFtpIp,    pFtpInfo->ulFtpPort,                             pFtpInfo->ucFtpUsr,   pFtpInfo->ucFtpPwd,                             pcRemotePath,           pcLocalPath,    ulMaxFileSize);          pResult = PyEval_CallObject(pFunction, pArgus);                   /*获取download下载结果*/         (void)PyArg_Parse(pResult,"i"，ulRet);     }     while(0);         Py_Finalize()          //xxxxxx记录日志     return ulRet; }      使用的是Python 的C API方法

user: user-1
content: 你的python代码是如何反馈进度的？ 是用print("10%")之类的方法输出的进度吗？ 还是用其他方式。 C代码是如何调用python的， 是通过Python/C API调用 还是把一个py文件当做可执行文件直接用ShellExecute之类的API去执行

user: user-2
content: 仅供参考：#pragma comment(lib,"user32") #include <stdio.h> #include <string.h> #include <windows.h> int main() {     SECURITY_ATTRIBUTES sa          = {0};     STARTUPINFO         si          = {0};     PROCESS_INFORMATION pi          = {0};     HANDLE              hPipeOutputRead  = NULL;     HANDLE              hPipeOutputWrite = NULL;     HANDLE              hPipeInputRead   = NULL;     HANDLE              hPipeInputWrite  = NULL;     BOOL                bTest = 0;     DWORD               dwNumberOfBytesRead = 0;     DWORD               dwNumberOfBytesWrite = 0;     CHAR                szMsg[100];     CHAR                szBuffer[256];      sa.nLength = sizeof(sa);     sa.bInheritHandle = TRUE;     sa.lpSecurityDescriptor = NULL;      // Create pipe for standard output redirection.     CreatePipe(&hPipeOutputRead,  // read handle             &hPipeOutputWrite, // write handle             &sa,      // security attributes             0      // number of bytes reserved for pipe - 0 default             );      // Create pipe for standard input redirection.     CreatePipe(&hPipeInputRead,  // read handle             &hPipeInputWrite, // write handle             &sa,      // security attributes             0      // number of bytes reserved for pipe - 0 default             );      // Make child process use hPipeOutputWrite as standard out,     // and make sure it does not show on screen.     si.cb = sizeof(si);     si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;     si.wShowWindow = SW_HIDE;     si.hStdInput   = hPipeInputRead;     si.hStdOutput  = hPipeOutputWrite;     si.hStdError   = hPipeOutputWrite;      CreateProcess (           NULL, "cmd.exe",           NULL, NULL,           TRUE, 0,           NULL, NULL,           &si, &pi);      // Now that handles have been inherited, close it to be safe.     // You don't want to read or write to them accidentally.     CloseHandle(hPipeOutputWrite);     CloseHandle(hPipeInputRead);      // Now test to capture DOS application output by reading     // hPipeOutputRead.  Could also write to DOS application     // standard input by writing to hPipeInputWrite.     sprintf(szMsg, "ver\n");     WriteFile(           hPipeInputWrite,      // handle of the write end of our pipe           &szMsg,               // address of buffer that send data           strlen(szMsg),        // number of bytes to write           &dwNumberOfBytesWrite,// address of number of bytes read           NULL                  // non-overlapped.           );      while(TRUE)     {        bTest=ReadFile(           hPipeOutputRead,      // handle of the read end of our pipe           &szBuffer,            // address of buffer that receives data           256,                  // number of bytes to read           &dwNumberOfBytesRead, // address of number of bytes read           NULL                  // non-overlapped.           );        if (!bTest){           sprintf(szMsg, "Error #%d reading pipe.",GetLastError());           printf("%s",szMsg);           break;       }        // do something with data.       szBuffer[dwNumberOfBytesRead] = 0;  // null terminate       printf("%s",szBuffer);       if ('>'==szBuffer[dwNumberOfBytesRead-1]) break;     }      sprintf(szMsg, "chcp\nexit\n");     WriteFile(           hPipeInputWrite,      // handle of the write end of our pipe           &szMsg,               // address of buffer that send data           strlen(szMsg),        // number of bytes to write           &dwNumberOfBytesWrite,// address of number of bytes read           NULL                  // non-overlapped.           );      while(TRUE)     {        bTest=ReadFile(           hPipeOutputRead,      // handle of the read end of our pipe           &szBuffer,            // address of buffer that receives data           256,                  // number of bytes to read           &dwNumberOfBytesRead, // address of number of bytes read           NULL                  // non-overlapped.           );        if (!bTest){           sprintf(szMsg, "Error #%d reading pipe.",GetLastError());           printf("%s",szMsg);           break;       }        // do something with data.       szBuffer[dwNumberOfBytesRead] = 0;  // null terminate       printf("%s",szBuffer);     }      // Wait for CONSPAWN to finish.     WaitForSingleObject (pi.hProcess, INFINITE);      // Close all remaining handles     CloseHandle (pi.hProcess);     CloseHandle (hPipeOutputRead);     CloseHandle (hPipeInputWrite);      return 0; } //C:\test>test //Microsoft Windows [版本 5.2.3790] //(C) 版权所有 1985-2003 Microsoft Corp. // //C:\test>ver // //Microsoft Windows [版本 5.2.3790] // //C:\test>chcp //活动的代码页: 936 // //C:\test>exit //Error #109 reading pipe. //C:\test>