Skip to content

Commit

Permalink
Fix new fundamental python deadlock 2 (#7548)
Browse files Browse the repository at this point in the history
Fix new fundamnental python history usecase deadlock
  • Loading branch information
Martin-Molinero authored Oct 31, 2023
1 parent c0801af commit 9f79016
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 20 deletions.
29 changes: 12 additions & 17 deletions Algorithm/QCAlgorithm.History.cs
Original file line number Diff line number Diff line change
Expand Up @@ -807,24 +807,25 @@ private IEnumerable<DataDictionary<T>> GetDataTypedHistory<T>(IEnumerable<Histor
private IEnumerable<Slice> History(IEnumerable<HistoryRequest> requests, DateTimeZone timeZone)
{
// filter out any universe securities that may have made it this far
var filteredRequests = GetFilterestRequests(requests, out var hasPythonDataRequest);
var filteredRequests = GetFilterestRequests(requests);

// filter out future data to prevent look ahead bias
var history = HistoryProvider.GetHistory(filteredRequests, timeZone);

if (hasPythonDataRequest && PythonEngine.IsInitialized)
if (PythonEngine.IsInitialized)
{
// add protection against potential python deadlocks
// with parallel history requests we reuse the data stack threads to serve the history calls because of this we need to make sure to release
// the GIL before waiting on the history request because there could be a work/job in the data stack queues which needs the GIL
return WrapPythonDataHistory(history);
}

return history;
}

private List<HistoryRequest> GetFilterestRequests(IEnumerable<HistoryRequest> requests, out bool hasPythonDataRequest)
private List<HistoryRequest> GetFilterestRequests(IEnumerable<HistoryRequest> requests)
{
List<HistoryRequest> result = new();
hasPythonDataRequest = false;
var sentMessage = false;
// filter out any universe securities that may have made it this far
Dictionary<Type, HistoryRequest> baseDataCollectionTypes = null;
Expand Down Expand Up @@ -866,11 +867,6 @@ private List<HistoryRequest> GetFilterestRequests(IEnumerable<HistoryRequest> re
{
result.Add(request);
}

if (!hasPythonDataRequest)
{
hasPythonDataRequest = request.IsCustomData && typeof(PythonData).IsAssignableFrom(request.DataType);
}
}

return result;
Expand Down Expand Up @@ -1209,20 +1205,19 @@ private static IEnumerable<Slice> WrapPythonDataHistory(IEnumerable<Slice> histo
{
using var enumerator = history.GetEnumerator();

var hasData = true;
while (hasData)
using (Py.GIL())
{
// TODO: we don't really need the GIL. We should find a way to check whether we have the lock and only call this wrapper method if we do.
using (Py.GIL())
var hasData = true;
while (hasData)
{
var state = PythonEngine.BeginAllowThreads();
hasData = enumerator.MoveNext();
PythonEngine.EndAllowThreads(state);
}

if (hasData)
{
yield return enumerator.Current;
if (hasData)
{
yield return enumerator.Current;
}
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions Engine/AlgorithmManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -838,11 +838,17 @@ private void HandleSplitSymbols(Splits newSplits, List<Split> splitWarnings)
{
if (split.Type != SplitType.Warning)
{
Log.Trace($"AlgorithmManager.HandleSplitSymbols(): {_algorithm.Time} - Security split occurred: Split Factor: {split} Reference Price: {split.ReferencePrice}");
if (Log.DebuggingEnabled)
{
Log.Debug($"AlgorithmManager.HandleSplitSymbols(): {_algorithm.Time} - Security split occurred: Split Factor: {split} Reference Price: {split.ReferencePrice}");
}
continue;
}

Log.Trace($"AlgorithmManager.HandleSplitSymbols(): {_algorithm.Time} - Security split warning: {split}");
if (Log.DebuggingEnabled)
{
Log.Debug($"AlgorithmManager.HandleSplitSymbols(): {_algorithm.Time} - Security split warning: {split}");
}

if (!splitWarnings.Any(x => x.Symbol == split.Symbol && x.Type == SplitType.Warning))
{
Expand Down
2 changes: 1 addition & 1 deletion Tests/Common/AlgorithmConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public void JsonSerialization()

var serialized = JsonConvert.SerializeObject(algorithmConfiguration);

Assert.AreEqual("{\"AccountCurrency\":\"GBP\",\"Brokerage\":12,\"AccountType\":1,\"Parameters\":{\"a\":\"A\",\"b\":\"B\"},\"OutOfSampleMaxEndDate\":\"2023-01-01T00:00:00\",\"OutOfSampleDays\":30,\"StartDate\":\"1998-01-01 00:00:00\",\"EndDate\":\"2023-10-26 23:59:59\"}", serialized);
Assert.AreEqual($"{{\"AccountCurrency\":\"GBP\",\"Brokerage\":12,\"AccountType\":1,\"Parameters\":{{\"a\":\"A\",\"b\":\"B\"}},\"OutOfSampleMaxEndDate\":\"2023-01-01T00:00:00\",\"OutOfSampleDays\":30,\"StartDate\":\"1998-01-01 00:00:00\",\"EndDate\":\"{algorithm.EndDate.ToString(DateFormat.UI)}\"}}", serialized);
}

private static TestCaseData[] AlgorithmConfigurationTestCases => new[]
Expand Down

0 comments on commit 9f79016

Please sign in to comment.