如何摆脱无限递归?
How to get ride of infinite recursion?
我有来自客户端的 OAuth2.0 Json 数据。而且我必须将所有数据从特定 API 提取到我的 SQL 数据库。这个 API 有一些验证,比如他们一次只能显示 250 个数据,接下来我们有 运行 API 再次使用不同的参数。
API 数据的结构是这样的。
{
"next": URL or null, // URL of the next page (same as the requested URL, but with the page query parameter incremented)
"previous": URL or null, // URL of the previous page
"results": array of result objects // the results follow the same format as `:endpoint/:id`
}
对于下一个或上一个数据,我们必须 运行 上一个或下一个 URL 出现。
我实现了将数据从 API 导入我的 SQL 数据的自动化。但是在一些循环之后我得到了这个错误。
在剩下的这些数据之后,我无法将其导入到我的 SQL 数据库中。
我正在努力 Dr.chrono API 将他们的数据导入我的系统。
我不知道该怎么办。
代码下方:-
private void recursivemethod(List<string> lstarray, String token, string URL, string flag, StringBuilder sb)
{
RestClient client = new RestClient(URL);
RestRequest request = new RestRequest(Method.GET);
request.Parameters.Clear();
client.Timeout = -1;
request.AddHeader("authorization", "Bearer " + token);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("cache-control", "no-cache");
IRestResponse response = client.Execute(request);
////Using dynamic keyword with JsonConvert.DeserializeObject, here you need to import Newtonsoft.Json
dynamic myObject = JsonConvert.DeserializeObject(response.Content);
if (flag == "patient")
{
PatientMain items = JsonConvert.DeserializeObject<PatientMain>(response.Content);
int i = 0;
lstarray.Clear();
foreach (var type in items.results)
{
i++;
lstarray.Add("INSERT INTO drchrono_patient(id,chart_id,first_name,middle_name,last_name,date_of_birth,gender,social_security_number,race,ethnicity,preferred_language,patient_status,home_phone,cell_phone,office_phone,email,address,city,state,zip_code,doctor,primary_care_physician,date_of_first_appointment,date_of_last_appointment,default_pharmacy,referring_source,copay,updated_at) VALUES ('" + convertQuotes(type.id) + "','" + convertQuotes(type.chart_id) + "','" + convertQuotes(type.first_name) + "','" + convertQuotes(type.middle_name) + "','" + convertQuotes(type.last_name) + "','" + convertQuotes(type.date_of_birth) + "','" + convertQuotes(type.gender) + "','" + convertQuotes(type.social_security_number) + "','" + convertQuotes(type.race) + "','" + convertQuotes(type.ethnicity) + "','" + convertQuotes(type.preferred_language) + "' ,'" + convertQuotes(type.patient_status) + "','" + convertQuotes(type.home_phone) + "','" + convertQuotes(type.cell_phone) + "','" + convertQuotes(type.office_phone) + "','" + convertQuotes(type.email) + "','" + convertQuotes(type.address) + "','" + convertQuotes(type.city) + "','" + convertQuotes(type.state) + "','" + convertQuotes(type.zip_code) + "','" + convertQuotes(type.doctor) + "','" + convertQuotes(type.primary_care_physician) + "','" + convertQuotes(type.date_of_first_appointment) + "','" + convertQuotes(type.date_of_last_appointment) + "','" + convertQuotes(type.default_pharmacy) + "','" + convertQuotes(type.referring_source) + "','" + convertQuotes(type.copay) + "','" + convertQuotes(type.updated_at) + "') ");
}
string result = dbf.pExecuteQueryList(lstarray);
if (items.next != null)
{
URL = items.next;
recursivemethod(lstarray, token, URL, flag, sb);
}
}
}
你有一个Whosebug
exception。来自微软文档:
The exception that is thrown when the execution stack overflows because it contains too many nested method calls.
在文档的后面
[...] typically in case of a very deep or unbounded recursion [..]
事实上,您的停止条件可能工作正常,只是在 execution stack(您的应用程序必须 运行 的内存量)已满之前根本不会达到。
通常,当应用程序运行时,每个不再使用的变量,数据结构,对象都从内存中删除,可以用来存储其他东西。
递归的问题在于,在递归完成之前,内存无法清空或优化,你的内存已满,并且在某个时候你 运行 out。
我不确定递归是不是一个好的选择,你可以简单地做一个循环,这样内存效率更高,允许系统在每次迭代之间清理内存。
如果您需要坚持递归,您应该考虑重新建模代码以将所有变量作为 reference 传递,否则执行堆栈将填满大量无用的复制数据,而您没有这样做需要复制。
考虑使用循环而不是递归。您可以保持大部分逻辑不变,只需重新构造您重复它的方式。让我们首先将方法签名更改为 return 一个值。这样的事情应该有效:
private string GetItems(List<string> lstarray, String token, string URL, string flag, StringBuilder sb)
并且在该方法中,return URL 值:
而不是递归自身
foreach (var type in items.results)
{
// your current loop, though be aware that you should update this to use query parameters
}
return item.next;
(在该方法的其他地方,您可以默认 return null;
以便所有代码路径 return 一个值。)
然后在概念上你的循环看起来像这样:
var url = "whatever your initial starting URL is";
while (url != null)
{
url = GetItems(lstarray, token, url, flag, sb);
}
基本上,这里真的不需要递归。您重复一个动作的次数未知,但该未知的动态值仍可用作循环条件,不需要递归。
我有来自客户端的 OAuth2.0 Json 数据。而且我必须将所有数据从特定 API 提取到我的 SQL 数据库。这个 API 有一些验证,比如他们一次只能显示 250 个数据,接下来我们有 运行 API 再次使用不同的参数。 API 数据的结构是这样的。
{
"next": URL or null, // URL of the next page (same as the requested URL, but with the page query parameter incremented)
"previous": URL or null, // URL of the previous page
"results": array of result objects // the results follow the same format as `:endpoint/:id`
}
对于下一个或上一个数据,我们必须 运行 上一个或下一个 URL 出现。
我实现了将数据从 API 导入我的 SQL 数据的自动化。但是在一些循环之后我得到了这个错误。
在剩下的这些数据之后,我无法将其导入到我的 SQL 数据库中。 我正在努力 Dr.chrono API 将他们的数据导入我的系统。 我不知道该怎么办。
代码下方:-
private void recursivemethod(List<string> lstarray, String token, string URL, string flag, StringBuilder sb)
{
RestClient client = new RestClient(URL);
RestRequest request = new RestRequest(Method.GET);
request.Parameters.Clear();
client.Timeout = -1;
request.AddHeader("authorization", "Bearer " + token);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("cache-control", "no-cache");
IRestResponse response = client.Execute(request);
////Using dynamic keyword with JsonConvert.DeserializeObject, here you need to import Newtonsoft.Json
dynamic myObject = JsonConvert.DeserializeObject(response.Content);
if (flag == "patient")
{
PatientMain items = JsonConvert.DeserializeObject<PatientMain>(response.Content);
int i = 0;
lstarray.Clear();
foreach (var type in items.results)
{
i++;
lstarray.Add("INSERT INTO drchrono_patient(id,chart_id,first_name,middle_name,last_name,date_of_birth,gender,social_security_number,race,ethnicity,preferred_language,patient_status,home_phone,cell_phone,office_phone,email,address,city,state,zip_code,doctor,primary_care_physician,date_of_first_appointment,date_of_last_appointment,default_pharmacy,referring_source,copay,updated_at) VALUES ('" + convertQuotes(type.id) + "','" + convertQuotes(type.chart_id) + "','" + convertQuotes(type.first_name) + "','" + convertQuotes(type.middle_name) + "','" + convertQuotes(type.last_name) + "','" + convertQuotes(type.date_of_birth) + "','" + convertQuotes(type.gender) + "','" + convertQuotes(type.social_security_number) + "','" + convertQuotes(type.race) + "','" + convertQuotes(type.ethnicity) + "','" + convertQuotes(type.preferred_language) + "' ,'" + convertQuotes(type.patient_status) + "','" + convertQuotes(type.home_phone) + "','" + convertQuotes(type.cell_phone) + "','" + convertQuotes(type.office_phone) + "','" + convertQuotes(type.email) + "','" + convertQuotes(type.address) + "','" + convertQuotes(type.city) + "','" + convertQuotes(type.state) + "','" + convertQuotes(type.zip_code) + "','" + convertQuotes(type.doctor) + "','" + convertQuotes(type.primary_care_physician) + "','" + convertQuotes(type.date_of_first_appointment) + "','" + convertQuotes(type.date_of_last_appointment) + "','" + convertQuotes(type.default_pharmacy) + "','" + convertQuotes(type.referring_source) + "','" + convertQuotes(type.copay) + "','" + convertQuotes(type.updated_at) + "') ");
}
string result = dbf.pExecuteQueryList(lstarray);
if (items.next != null)
{
URL = items.next;
recursivemethod(lstarray, token, URL, flag, sb);
}
}
}
你有一个Whosebug
exception。来自微软文档:
The exception that is thrown when the execution stack overflows because it contains too many nested method calls.
在文档的后面
[...] typically in case of a very deep or unbounded recursion [..]
事实上,您的停止条件可能工作正常,只是在 execution stack(您的应用程序必须 运行 的内存量)已满之前根本不会达到。
通常,当应用程序运行时,每个不再使用的变量,数据结构,对象都从内存中删除,可以用来存储其他东西。
递归的问题在于,在递归完成之前,内存无法清空或优化,你的内存已满,并且在某个时候你 运行 out。
我不确定递归是不是一个好的选择,你可以简单地做一个循环,这样内存效率更高,允许系统在每次迭代之间清理内存。
如果您需要坚持递归,您应该考虑重新建模代码以将所有变量作为 reference 传递,否则执行堆栈将填满大量无用的复制数据,而您没有这样做需要复制。
考虑使用循环而不是递归。您可以保持大部分逻辑不变,只需重新构造您重复它的方式。让我们首先将方法签名更改为 return 一个值。这样的事情应该有效:
private string GetItems(List<string> lstarray, String token, string URL, string flag, StringBuilder sb)
并且在该方法中,return URL 值:
而不是递归自身foreach (var type in items.results)
{
// your current loop, though be aware that you should update this to use query parameters
}
return item.next;
(在该方法的其他地方,您可以默认 return null;
以便所有代码路径 return 一个值。)
然后在概念上你的循环看起来像这样:
var url = "whatever your initial starting URL is";
while (url != null)
{
url = GetItems(lstarray, token, url, flag, sb);
}
基本上,这里真的不需要递归。您重复一个动作的次数未知,但该未知的动态值仍可用作循环条件,不需要递归。